Compare commits

...

129 commits

Author SHA1 Message Date
ad4ba073a3 Add nameof module support
Some checks failed
macos / macos-13 (push) Has been cancelled
macos / macos-14 (push) Has been cancelled
ubuntu / clang-10 (push) Has been cancelled
ubuntu / clang-11 (push) Has been cancelled
ubuntu / clang-12 (push) Has been cancelled
ubuntu / clang-13 (push) Has been cancelled
ubuntu / clang-14 (push) Has been cancelled
ubuntu / clang-15 (push) Has been cancelled
ubuntu / clang-16 (push) Has been cancelled
ubuntu / clang-9 (push) Has been cancelled
ubuntu / gcc-10 (push) Has been cancelled
ubuntu / gcc-11 (push) Has been cancelled
ubuntu / gcc-12 (push) Has been cancelled
ubuntu / gcc-13 (push) Has been cancelled
ubuntu / gcc-14 (push) Has been cancelled
ubuntu / gcc-9 (push) Has been cancelled
windows / Visual Studio 2019 (push) Has been cancelled
windows / Visual Studio 2022 (push) Has been cancelled
2024-10-19 23:02:24 +00:00
neargye
6c8e87da57 update ci 2024-10-14 15:38:45 +03:00
neargye
3f1664327a use cstring for allow NTTP 2024-09-19 13:52:06 +03:00
neargye
174b23d76e clean-up 2024-05-16 00:10:36 +03:00
neargye
3d4c9820fc v0.10.4 2024-01-31 18:26:52 +04:00
neargye
72a9659576 update ci 2024-01-31 18:26:46 +04:00
neargye
72ce6c9ae0 update readme 2024-01-31 18:26:39 +04:00
neargye
4d097b9da0 update copyright 2024-01-02 02:51:35 +04:00
neargye
e86b94cb8d update readme 2024-01-02 02:45:25 +04:00
Daniil Goncharov
c9ae9a57c3
add support big enum range (#65) 2023-12-01 01:33:57 +04:00
SF-Zhou
5443409085
Fix enum flags example in README.md (#63) 2023-09-21 11:55:14 +04:00
Bela Schaum
8aeb677413
Replace union type holder to template extern variable (#62) 2023-06-23 16:10:32 +04:00
neargye
f2522c2cc0 * add sep param to nameof_enum_flag
* fix noexcept
2023-06-14 02:44:15 +04:00
neargye
8a6813f242 update ci 2023-05-27 14:15:05 +04:00
neargye
31ac2b3273 update readme 2023-05-26 17:40:33 +04:00
neargye
8f416c881e v0.10.3 2023-03-30 20:19:30 +04:00
neargye
6708611448 update doc 2023-03-30 19:10:22 +04:00
Bela Schaum
1f071407dc
Nameof pointer + tests (#59) 2023-03-17 21:39:30 +04:00
Bela Schaum
9494cbd4aa
Add a static assertion for issue https://github.com/Neargye/nameof/issues/52 (#57) 2023-03-06 17:02:46 +04:00
Joshua Saxby
84ce6d87fb
Improve grammar for limitations (#56)
I am completely unfamiliar with this project but I am a native English speaker, hopefully I understood the original document and my proposed changes improve the grammar without changing the meaning.
2023-02-22 23:15:02 +04:00
KOLANICH
173271ef06
Fix forgotten replacement in CPack packaging script (#55) 2023-02-16 17:38:39 +04:00
neargye
a83b66aac9 update ci 2023-01-31 22:49:07 +04:00
Dirk Stolle
34d8c2b74e
Update actions/checkout in GitHub Actions workflows to v3 (#54) 2023-01-27 03:50:25 +04:00
Dirk Stolle
1cc3feb884
fix typo in example (#53) 2023-01-27 03:37:48 +04:00
KOLANICH
b877a1a556
Added CPack and pkg-config packaging. (#44) 2023-01-17 16:48:17 +04:00
neargye
bc183cd334 clean-up 2022-12-07 01:30:25 +04:00
kamchatka-volcano
70ca094db8
Fix #49 (#50) 2022-12-07 01:24:06 +04:00
Bela Schaum
f7b2f34053
Fix https://github.com/Neargye/nameof/issues/46 (#48) 2022-11-13 21:01:31 +04:00
neargye
84c2d8bb19 update doc 2022-11-08 13:01:28 +04:00
neargye
6a1efd31c1 clean-up 2022-09-02 17:26:22 +04:00
neargye
ea3871026a fix IntelliSence 2022-08-15 12:38:17 +04:00
neargye
54a6a795a9 clean-up 2022-08-14 15:54:27 +04:00
neargye
f14c1b5065 fix build 2022-08-13 19:26:45 +04:00
neargye
00a333bb8e add aliases test 2022-08-13 18:18:52 +04:00
neargye
09f879a995 fix clang trunk build 2022-08-12 21:46:36 +04:00
neargye
3237b9a367 update ci 2022-08-12 21:38:40 +04:00
neargye
db94e8b345 fix clang llvm-project#50055(reviews.llvm.org/D131307) 2022-08-12 21:38:20 +04:00
neargye
4d2d89eac7 ignored "-Wenum-constexpr-conversion" 2022-08-09 15:47:25 +04:00
neargye
c44b65d57d fix clang llvm-project#50055(reviews.llvm.org/D130058) 2022-08-09 15:28:23 +04:00
neargye
c04b72fc51 v0.10.2 2022-08-04 17:32:59 +04:00
neargye
b6a4452eef update doc
fix noexcept nameof_enum_or
2022-07-26 18:48:58 +04:00
neargye
59411bf519 add nameof_enum_or 2022-07-26 18:17:36 +04:00
Bela Schaum
f32bbb0f09
Try to fix tests (#43) 2022-07-25 14:07:57 +04:00
neargye
c793b69c40 fix 2022-07-25 01:10:57 +04:00
neargye
2cb9751cb6 add nameof_member for mscv and c++20 2022-07-21 21:07:19 +04:00
neargye
32885c092e update ci 2022-07-21 20:01:56 +04:00
neargye
5bf352dfa6 fix #39 2022-07-21 19:55:02 +04:00
neargye
7e2cc11360 fix warnings 2022-06-29 16:40:42 +04:00
neargye
83ee9b42df update copyright 2022-06-10 18:15:37 +04:00
neargye
e37861d46f clean-up 2022-05-18 22:30:04 +04:00
neargye
3a728f4102 clean-up 2022-05-18 18:31:02 +04:00
neargye
b5deb0055c fix build 2022-05-18 16:28:56 +04:00
neargye
b12d458de0 * fix vs2022 build
* clean-up
2022-05-18 16:26:40 +04:00
Daniil Goncharov
22c8c79c15
update readme 2022-04-30 19:41:39 +04:00
neargye
ed238a058b update readme 2022-04-19 22:51:06 +04:00
neargye
6422949948 update ci 2022-04-03 01:26:59 +04:00
neargye
143d19c5e0 update copyright 2022-04-03 01:26:52 +04:00
neargye
d99ab9ae73 update compiler compatibility 2022-04-03 01:26:37 +04:00
Daniil Goncharov
286c76eef9
Update README.md 2022-03-02 21:26:22 +02:00
Daniil Goncharov
7ea354b14f update 2022-01-24 22:59:49 +02:00
neargye
ef84cb110b update ci 2022-01-23 17:38:38 +02:00
neargye
bd14db23e1 update 2022-01-22 19:22:24 +02:00
neargye
b19b00b61a Fix underflow in out of range check
Fix bool special case
2021-06-26 12:03:55 +03:00
neargye
e009769d00 update readme 2021-06-26 11:42:57 +03:00
neargye
292d604578 v0.10.1 2021-06-21 20:49:27 +03:00
neargye
12bb8c0df3 update ci and cmake 2021-06-21 20:49:09 +03:00
neargye
d69f91daa5 fix typo 2021-05-07 11:17:35 +03:00
neargye
6810459778 fix using leak 2021-04-28 20:51:50 +03:00
neargye
a9813bd7a1 fix range check 2021-04-22 12:41:25 +03:00
neargye
d091ca081e fix hard error if enum is empty or non-reflected 2021-04-22 12:23:54 +03:00
neargye
b61944a3b6 update catch2 to 2.13.4 for Apple Silicon support 2021-04-14 14:01:50 +03:00
neargye
71ae34dbe8 add AUR package info, thanks @CHN-beta 2021-04-11 18:01:30 +03:00
neargye
dad9b4b044 remove old ci 2021-04-11 17:59:01 +03:00
neargye
84c6c9866a fix checks 2021-04-03 00:37:30 +03:00
neargye
bb413bbdaa fix tests 2021-04-03 00:33:05 +03:00
neargye
fb480caab2 fix checks 2021-04-03 00:32:17 +03:00
neargye
df0ea27383 fix build 2021-04-03 00:29:27 +03:00
neargye
2cf013dbf3 add nameof_member 2021-04-03 00:17:18 +03:00
neargye
6df582978d update ci 2021-04-03 00:00:23 +03:00
neargye
f57dcf410a workaround std::array in some cases is missing constexpr on some of its functions 2021-03-10 11:39:56 +02:00
neargye
3a52b520c9 fix #31 2021-01-24 08:39:43 +02:00
neargye
b94b243525 update copyright 2021-01-24 08:39:23 +02:00
Daniil Goncharov
7b5d24e37f
v0.10.0 (#30)
v0.10.0
2021-01-12 10:39:52 +02:00
Daniil Goncharov
6fa49cca4b
Wip v0.10.0 (#28) 2020-12-29 20:45:54 +02:00
neargye
308bbf9c68 update 2020-12-24 16:27:20 +02:00
neargye
3986a3ce93 update ci 2020-11-18 11:09:58 +02:00
neargye
0ba625e215 update ci 2020-11-15 22:54:48 +02:00
Daniil Goncharov
8d2044f2d7
Create FUNDING.yml 2020-11-09 15:26:20 +02:00
Ubpa
0e8bec0dc0
export (#26)
make the project to be used from a build directory
reference: https://cmake.org/cmake/help/latest/guide/tutorial/index.html#adding-export-configuration-step-11
2020-11-02 19:01:39 +02:00
neargye
02e33b6b18 add nameof_short_type 2020-09-07 20:35:21 +03:00
neargye
e814a3c13d clean-up 2020-09-07 20:12:54 +03:00
Daniil Goncharov
0ccc3b4f3b
clean-up 2020-09-01 14:00:59 +03:00
neargye
1fafaba65d fix cmake config 2020-07-06 10:55:00 +05:00
Daniil Goncharov
74dfbd6528
add nameof_enum_flag 2020-07-03 18:18:05 +05:00
neargye
5de9eb6291 clean-up 2020-06-27 16:12:35 +05:00
neargye
7daf306654 now in conan-center 2020-06-27 11:26:23 +05:00
neargye
735ba9fb1d update readme 2020-06-26 21:37:48 +05:00
neargye
fff49040ed fix warnings 2020-06-18 15:34:22 +05:00
neargye
7614db16d1 update ci 2020-06-18 15:12:02 +05:00
neargye
abac0c52b6 update readme 2020-06-09 14:38:27 +05:00
neargye
faf5a52b91 update ci 2020-06-09 14:38:18 +05:00
neargye
e97a790afb v0.9.4 2020-06-06 16:27:54 +05:00
neargye
ed04f81ff7 update type name rtti 2020-06-06 16:14:16 +05:00
neargye
d12b28c346 clean-up 2020-06-06 15:41:29 +05:00
neargye
f4f4908d7e clean-up NAMEOF_TYPE_RTTI 2020-06-05 15:24:13 +05:00
neargye
d099f13d12 clean-up 2020-06-03 20:04:09 +05:00
neargye
c42376a8d1 improve compiler check 2020-06-03 19:51:05 +05:00
neargye
59f176a10f fix test 2020-06-03 19:49:13 +05:00
neargye
7bf624de33 wip NAMEOF_TYPE_RTTI 2020-06-03 19:33:01 +05:00
neargye
2cdcdc0f83 add NAMEOF_TYPE_RTTI 2020-06-03 19:25:30 +05:00
neargye
77fd770012 fix readme 2020-06-03 15:00:31 +05:00
neargye
18cfc68c65 more consistent 2020-05-27 16:22:29 +05:00
neargye
3e2fa48b37 fix cstring 2020-05-24 17:52:39 +05:00
neargye
9ede5ab901 clean-up namespace 2020-05-24 17:52:22 +05:00
neargye
121166d263 fix decay 2020-05-23 18:06:12 +05:00
Daniil Goncharov
a47f23bc6d
improve nameof_enum (#20)
improve nameof_enum
2020-05-23 17:56:46 +05:00
neargye
e2a56fa18a update doc 2020-05-12 13:48:55 +05:00
neargye
f7aa276086 update readme 2020-05-01 18:06:34 +05:00
neargye
51a79f9545 remove duplicated code 2020-04-30 19:46:46 +05:00
neargye
dc127d3d4d improve mixed_sign_less 2020-04-18 13:45:15 +05:00
neargye
7da39ee9ba add CPM 2020-04-06 14:02:48 +05:00
neargye
66a61bf7f2 update copyright 2020-02-25 15:53:42 +05:00
neargye
1b8b849184 update doc 2020-02-14 18:04:48 +05:00
neargye
6e97229efd more friendly static checks 2020-02-14 15:28:16 +05:00
Neargye
9885d98bf3 clean-up 2020-01-31 15:16:38 +05:00
Neargye
1303731a6b improve conan compiler version check 2020-01-31 15:16:35 +05:00
Daniil Goncharov
ef959f7da5
update ci 2020-01-29 15:33:59 +05:00
Neargye
f9078cc9f9 update doc 2020-01-25 23:48:12 +05:00
neargye
04578f3316 fix code style 2020-01-15 15:42:14 +05:00
29 changed files with 4396 additions and 1949 deletions

View file

@ -1,26 +0,0 @@
version: "{branch} #{build}"
image:
- Visual Studio 2017
- Visual Studio 2019
platform:
- Win32
- x64
build:
parallel: true
before_build:
- if exist build RMDIR /S /Q build
- if not exist build mkdir build
- cd build
build_script:
- cmake -A %PLATFORM% ..
- cmake --build . --config Debug
- cmake --build . --config Release
test_script:
- ctest --output-on-failure -C Debug
- ctest --output-on-failure -C Release

37
.github/workflows/macos.yml vendored Normal file
View file

@ -0,0 +1,37 @@
name: macos
on: [push, pull_request]
permissions: read-all
jobs:
build:
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- { os: macos-13 } # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-13-Readme.md#xcode
- { os: macos-14 } # https://github.com/actions/virtual-environments/blob/main/images/macos/macos-14-Readme.md#xcode
name: "${{ matrix.config.os }}"
steps:
- uses: actions/checkout@v4
- name: Build Release
run: |
rm -rf build
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
cmake --build . -j 4 --config Release
ctest --output-on-failure -C Release
- name: Build Debug
run: |
rm -rf build
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug
cmake --build . -j 4 --config Debug
ctest --output-on-failure -C Debug

76
.github/workflows/ubuntu.yml vendored Normal file
View file

@ -0,0 +1,76 @@
name: ubuntu
on: [push, pull_request]
permissions: read-all
jobs:
ubuntu:
strategy:
fail-fast: false
matrix:
compiler:
- { cc: "gcc-9", cxx: "g++-9", os: "ubuntu-20.04" }
- { cc: "gcc-10", cxx: "g++-10", os: "ubuntu-20.04" }
- { cc: "gcc-10", cxx: "g++-10", os: "ubuntu-20.04" }
- { cc: "gcc-11", cxx: "g++-11", os: "ubuntu-20.04" }
- { cc: "gcc-11", cxx: "g++-11", os: "ubuntu-20.04" }
- { cc: "gcc-12", cxx: "g++-12", os: "ubuntu-22.04" }
- { cc: "gcc-13", cxx: "g++-12", os: "ubuntu-22.04" }
- { cc: "gcc-14", cxx: "g++-12", os: "ubuntu-22.04" }
- { cc: "clang-9", cxx: "clang++-9", os: "ubuntu-20.04" }
- { cc: "clang-10", cxx: "clang++-10", os: "ubuntu-20.04" }
- { cc: "clang-11", cxx: "clang++-11", os: "ubuntu-20.04" }
- { cc: "clang-12", cxx: "clang++-12", os: "ubuntu-20.04" }
- { cc: "clang-13", cxx: "clang++-13", os: "ubuntu-20.04" }
- { cc: "clang-14", cxx: "clang++-14", os: "ubuntu-20.04" }
- { cc: "clang-15", cxx: "clang++-15", os: "ubuntu-20.04" }
- { cc: "clang-16", cxx: "clang++-16", os: "ubuntu-20.04" }
name: "${{ matrix.compiler.cc }}"
runs-on: ${{ matrix.compiler.os }}
steps:
- uses: actions/checkout@v4
- name: Configure clang
run: |
if [[ "${{ matrix.compiler.cc }}" == "clang"* ]]; then
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add -
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-9 main"
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-10 main"
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-11 main"
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-12 main"
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-13 main"
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-14 main"
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-15 main"
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal-16 main"
sudo apt-add-repository "deb http://apt.llvm.org/focal/ llvm-toolchain-focal main"
sudo apt update
sudo apt install ${{ matrix.compiler.cc }} -y
fi
- name: Configure gcc
run: |
if [[ "${{ matrix.compiler.cc }}" == "gcc"* ]]; then
sudo add-apt-repository ppa:ubuntu-toolchain-r/test -y
sudo apt update
sudo apt install ${{ matrix.compiler.cxx }} -y
fi
- name: Build Release
run: |
rm -rf build
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }}
cmake --build . -j 4 --config Release
ctest --output-on-failure -C Release
- name: Build Debug
run: |
rm -rf build
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_COMPILER=${{ matrix.compiler.cxx }}
cmake --build . -j 4 --config Debug
ctest --output-on-failure -C Debug

43
.github/workflows/windows.yml vendored Normal file
View file

@ -0,0 +1,43 @@
name: windows
on: [push, pull_request]
permissions: read-all
jobs:
build:
runs-on: ${{ matrix.config.os }}
strategy:
fail-fast: false
matrix:
config:
- { os: windows-2019, vs: "Visual Studio 2019" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2019-Readme.md#visual-studio-enterprise-2019
- { os: windows-2022, vs: "Visual Studio 2022" } # https://github.com/actions/virtual-environments/blob/main/images/win/Windows2022-Readme.md#visual-studio-enterprise-2022
name: "${{ matrix.config.vs }}"
steps:
- uses: actions/checkout@v4
- name: Build Win32
shell: bash
run: |
rm -rf build
mkdir build
cd build
cmake .. -A Win32
cmake --build . -j 4 --config Release
ctest --output-on-failure -C Release
cmake --build . -j 4 --config Debug
ctest --output-on-failure -C Debug
- name: Build x64
shell: bash
run: |
rm -rf build
mkdir build
cd build
cmake .. -A x64
cmake --build . -j 4 --config Release
ctest --output-on-failure -C Release
cmake --build . -j 4 --config Debug
ctest --output-on-failure -C Debug

View file

@ -1,144 +0,0 @@
os: linux # Use linux unless specified otherwise.
dist: xenial
sudo: required
language: cpp
matrix:
include:
- os: linux
compiler: g++
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-7
env:
- CXX_COMPILER=g++-7 CC_COMPILER=gcc-7
- os: linux
compiler: g++
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-8
env:
- CXX_COMPILER=g++-8 CC_COMPILER=gcc-8
- os: linux
compiler: g++
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- g++-9
env:
- CXX_COMPILER=g++-9 CC_COMPILER=gcc-9
- os: linux
compiler: clang++
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-5.0 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- g++-7
- clang-5.0
env:
- CXX_COMPILER=clang++-5.0 CC_COMPILER=clang-5.0
- os: linux
compiler: clang++
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-6.0 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- g++-7
- clang-6.0
env:
- CXX_COMPILER=clang++-6.0 CC_COMPILER=clang-6.0
- os: linux
compiler: clang++
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-7 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- g++-7
- clang-7
env:
- CXX_COMPILER=clang++-7 CC_COMPILER=clang-7
- os: linux
compiler: clang++
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-8 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- g++-7
- clang-8
env:
- CXX_COMPILER=clang++-8 CC_COMPILER=clang-8
- os: linux
compiler: clang++
addons:
apt:
sources:
- ubuntu-toolchain-r-test
- sourceline: 'deb https://apt.llvm.org/xenial/ llvm-toolchain-xenial-9 main'
key_url: 'https://apt.llvm.org/llvm-snapshot.gpg.key'
packages:
- g++-7
- clang-9
env:
- CXX_COMPILER=clang++-9 CC_COMPILER=clang-9
- os: osx
compiler: clang++
osx_image: xcode10.3
env:
- CXX_COMPILER=clang++ CC_COMPILER=clang
- os: osx
compiler: clang++
osx_image: xcode11.2
env:
- CXX_COMPILER=clang++ CC_COMPILER=clang
install:
- export CC=${CC_COMPILER}
- export CXX=${CXX_COMPILER}
- JOBS=2 # Travis machines have 2 cores.
before_script:
- rm -rf build
- mkdir -p build
- cd build
script:
- cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Debug ..
- cmake --build . --config Debug -- -j${JOBS}
- ctest --output-on-failure -C Debug -j${JOBS}
- rm -rf ./*
- cmake -G "Unix Makefiles" -DCMAKE_BUILD_TYPE=Release ..
- cmake --build . --config Release -- -j${JOBS}
- ctest --output-on-failure -C Release -j${JOBS}
notifications:
email: false

View file

@ -1,6 +1,17 @@
cmake_minimum_required(VERSION 3.8)
cmake_minimum_required(VERSION 3.30)
project(nameof VERSION "0.9.3" LANGUAGES CXX)
include(GNUInstallDirs)
set(ADDITIONAL_MODULES_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake")
list(APPEND CMAKE_MODULE_PATH "${ADDITIONAL_MODULES_DIR}")
project(nameof
VERSION "0.10.4"
HOMEPAGE_URL "https://github.com/Neargye/nameof"
DESCRIPTION "A library that provides nameof macros and functions to simply obtain the name of a variable, type, function, macro, and enum."
LANGUAGES CXX
)
set(CPACK_PACKAGE_VENDOR "Daniil Goncharov")
if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME)
set(IS_TOPLEVEL_PROJECT TRUE)
@ -10,6 +21,8 @@ endif()
option(NAMEOF_OPT_BUILD_EXAMPLES "Build nameof examples" ${IS_TOPLEVEL_PROJECT})
option(NAMEOF_OPT_BUILD_TESTS "Build and perform nameof tests" ${IS_TOPLEVEL_PROJECT})
option(NAMEOF_OPT_INSTALL "Generate and install nameof target" ${IS_TOPLEVEL_PROJECT})
option(NAMEOF_MODULE "Build nameof module" OFF)
if(NAMEOF_OPT_BUILD_EXAMPLES)
add_subdirectory(example)
@ -22,27 +35,119 @@ endif()
include(CMakePackageConfigHelpers)
add_library(${PROJECT_NAME} INTERFACE)
add_library(${PROJECT_NAME}::${PROJECT_NAME} ALIAS ${PROJECT_NAME})
target_compile_features(${PROJECT_NAME} INTERFACE cxx_std_17)
target_include_directories(${PROJECT_NAME}
set(EXPORT_NAMESPACE "${PROJECT_NAME}::")
set(INCLUDES "${CMAKE_CURRENT_SOURCE_DIR}/include")
if(NAMEOF_MODULE)
set(CMAKE_CXX_EXTENSIONS OFF)
add_library(${PROJECT_NAME})
target_include_directories(${PROJECT_NAME}
PUBLIC
$<BUILD_INTERFACE:${INCLUDES}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
target_compile_definitions(${PROJECT_NAME} PRIVATE NAMEOF_MODULE)
target_compile_features(${PROJECT_NAME} PUBLIC cxx_std_20)
target_sources(${PROJECT_NAME} PUBLIC FILE_SET nameofModules TYPE CXX_MODULES
FILES src/nameof.cpp)
else()
add_library("${PROJECT_NAME}" INTERFACE)
target_include_directories(${PROJECT_NAME}
INTERFACE
$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>
$<INSTALL_INTERFACE:include>)
$<BUILD_INTERFACE:${INCLUDES}>
$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>)
endif()
write_basic_package_version_file(${PROJECT_NAME}ConfigVersion.cmake
VERSION ${PROJECT_VERSION}
COMPATIBILITY AnyNewerVersion)
add_library("${EXPORT_NAMESPACE}${PROJECT_NAME}" ALIAS "${PROJECT_NAME}")
install(TARGETS ${PROJECT_NAME}
EXPORT ${PROJECT_NAME}Config)
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake
DESTINATION lib/cmake/${PROJECT_NAME})
install(EXPORT ${PROJECT_NAME}Config
NAMESPACE ${PROJECT_NAME}::
DESTINATION lib/cmake/${PROJECT_NAME})
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/include
DESTINATION .)
if(NAMEOF_OPT_INSTALL)
list(APPEND CMAKE_MODULE_PATH "${ADDITIONAL_MODULES_DIR}/GenPkgConfig")
include(GenPkgConfig)
include(CPackComponent)
include(CMakePackageConfigHelpers)
string(REPLACE "/${CMAKE_LIBRARY_ARCHITECTURE}" "" CMAKE_INSTALL_LIBDIR_ARCHIND "${CMAKE_INSTALL_LIBDIR}")
install(TARGETS "${PROJECT_NAME}"
EXPORT ${PROJECT_NAME}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
FILE_SET nameofModules DESTINATION ${CMAKE_INSTALL_LIBDIR}
INCLUDES
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}"
# COMPONENT "${SDK_COMPONENT_NAME}" # component is not allowed for includes! Headers are installed separately! Includes only marks the headers for export
)
file(GLOB_RECURSE HEADERS "${INCLUDES}/*.h" "${INCLUDES}/*.hxx" "${INCLUDES}/*.hpp")
foreach(headerFile ${HEADERS})
get_filename_component(headerFileParentDir "${headerFile}" DIRECTORY)
file(RELATIVE_PATH headerFileRelParentDir "${INCLUDES}" "${headerFileParentDir}")
install(FILES "${headerFile}"
DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}/${headerFileRelParentDir}"
)
endforeach()
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
set(CPACK_PACKAGE_DESCRIPTION "${PROJECT_DESCRIPTION}")
set(CPACK_DEBIAN_PACKAGE_ARCHITECTURE "all")
set(CPACK_DEBIAN_PACKAGE_NAME "lib${CPACK_PACKAGE_NAME}-dev")
set(CPACK_RPM_PACKAGE_NAME "lib${CPACK_PACKAGE_NAME}-devel")
set(CPACK_PACKAGE_HOMEPAGE_URL "${PROJECT_HOMEPAGE_URL}")
set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}")
set(CPACK_DEBIAN_PACKAGE_DEPENDS "")
set(CPACK_DEBIAN_PACKAGE_MAINTAINER "${CPACK_PACKAGE_MAINTAINER}")
set(CPACK_PACKAGE_MAINTAINER "${CPACK_PACKAGE_VENDOR}")
set(CPACK_DEB_COMPONENT_INSTALL ON)
set(CPACK_RPM_COMPONENT_INSTALL ON)
set(CPACK_NSIS_COMPONENT_INSTALL ON)
set(CPACK_DEBIAN_COMPRESSION_TYPE "xz")
set(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/LICENSE")
set(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README.md")
set(CMAKE_CONFIG_FILE_BASENAME "${PROJECT_NAME}Config.cmake")
set(CMAKE_EXPORT_FILE_BASENAME "${PROJECT_NAME}Export.cmake")
set(CMAKE_CONFIG_VERSION_FILE_BASENAME "${PROJECT_NAME}ConfigVersion.cmake")
set(CMAKE_CONFIG_VERSION_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_CONFIG_VERSION_FILE_BASENAME}")
export(TARGETS "${PROJECT_NAME}"
NAMESPACE "${EXPORT_NAMESPACE}"
FILE "${CMAKE_EXPORT_FILE_BASENAME}"
EXPORT_LINK_INTERFACE_LIBRARIES
)
install(EXPORT "${PROJECT_NAME}"
FILE "${CMAKE_CONFIG_FILE_BASENAME}"
NAMESPACE "${EXPORT_NAMESPACE}"
DESTINATION "${CMAKE_INSTALL_LIBDIR_ARCHIND}/cmake/${PROJECT_NAME}"
)
write_basic_package_version_file(
"${CMAKE_CONFIG_VERSION_FILE_NAME}"
#VERSION "100500.100500.100500" # any version of same bitness suits. CMake cannot compare to infinity, so use a large number we expect to be greater than any future version
VERSION ${_VERSION}
COMPATIBILITY AnyNewerVersion
ARCH_INDEPENDENT
)
install(FILES "${CMAKE_CONFIG_VERSION_FILE_NAME}"
DESTINATION "${CMAKE_INSTALL_LIBDIR_ARCHIND}/cmake/${PROJECT_NAME}"
)
configure_pkg_config_file("${PROJECT_NAME}"
NAME "${PROJECT_NAME}"
VERSION "${PROJECT_VERSION}"
DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}"
URL "${CPACK_PACKAGE_HOMEPAGE_URL}"
INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR_ARCHIND}"
INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}"
)
include(CPack)
endif()

View file

@ -1,6 +1,6 @@
MIT License
Copyright (c) 2016, 2018 - 2019 Daniil Goncharov
Copyright (c) 2016 - 2024 Daniil Goncharov
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal

132
README.md
View file

@ -1,37 +1,15 @@
```text
_ _ __ _____
| \ | | / _| / ____|_ _
| \| | __ _ _ __ ___ ___ ___ | |_ | | _| |_ _| |_
| . ` |/ _` | '_ ` _ \ / _ \/ _ \| _| | | |_ _|_ _|
| |\ | (_| | | | | | | __/ (_) | | | |____|_| |_|
|_| \_|\__,_|_| |_| |_|\___|\___/|_| \_____|
```
[![Github releases](https://img.shields.io/github/release/Neargye/nameof.svg)](https://github.com/Neargye/nameof/releases)
[![Conan package](https://img.shields.io/badge/Conan-package-blueviolet)](https://bintray.com/neargye/conan-packages/nameof:neargye)
[![Conan package](https://img.shields.io/badge/Conan-package-blueviolet)](https://conan.io/center/recipes/nameof)
[![Vcpkg package](https://img.shields.io/badge/Vcpkg-package-blueviolet)](https://github.com/microsoft/vcpkg/tree/master/ports/nameof)
[![License](https://img.shields.io/github/license/Neargye/nameof.svg)](LICENSE)
[![Build status](https://travis-ci.org/Neargye/nameof.svg?branch=master)](https://travis-ci.org/Neargye/nameof)
[![Build status](https://ci.appveyor.com/api/projects/status/yq5fk0d9mwljbubt/branch/master?svg=true)](https://ci.appveyor.com/project/Neargye/nameof/branch/master)
[![Codacy badge](https://api.codacy.com/project/badge/Grade/1d06f3f07afe4f34acd29c0c8efa830b)](https://www.codacy.com/app/Neargye/nameof?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=Neargye/nameof&amp;utm_campaign=Badge_Grade)
[![Try online](https://img.shields.io/badge/try-online-blue.svg)](https://wandbox.org/permlink/p4k7LC9w0BO4UJgo)
[![Compiler explorer](https://img.shields.io/badge/compiler_explorer-online-blue.svg)](https://godbolt.org/z/s_ecko)
[![Stand With Ukraine](https://raw.githubusercontent.com/vshymanskyy/StandWithUkraine/main/badges/StandWithUkraine.svg)](https://stand-with-ukraine.pp.ua)
# Nameof C++
Header-only C++17 library provides nameof macros and functions to simply obtain the name of a variable, type, function, macro, and enum.
## Features
* C++17
* Header-only
* Dependency-free
* Compile-time
* Name of variable, member variable
* Name of type, variable type
* Name of function, member function
* Name of enum, enum variable
* Name of macro
* Enum to string
If you like this project, please consider donating to one of the funds that help victims of the war in Ukraine: https://u24.gov.ua.
## Documentation
@ -39,9 +17,10 @@ Header-only C++17 library provides nameof macros and functions to simply obtain
* [Limitations](doc/limitations.md)
* [Integration](#Integration)
## [Examples](example/example.cpp)
## [Features & Examples](example/example.cpp)
* Nameof
```cpp
// Name of variable.
NAMEOF(somevar) -> "somevar"
@ -59,10 +38,19 @@ Header-only C++17 library provides nameof macros and functions to simply obtain
// Name of macro.
NAMEOF(__LINE__) -> "__LINE__"
NAMEOF(NAMEOF(structvar)) -> "NAMEOF"
// Obtains full name of variable, function, macro.
NAMEOF_FULL(somevar.some_method<int>()) -> "some_method<int>"
// Obtains raw name of variable, function, macro.
NAMEOF_RAW(somevar.some_method<int>()) -> "somevar.some_method<int>()"
```
* Nameof enum
```cpp
enum class Color { RED = 1, BLUE = 2, GREEN = 4 };
auto color = Color::RED;
// Name of enum variable.
NAMEOF_ENUM(color) -> "RED"
@ -70,38 +58,65 @@ Header-only C++17 library provides nameof macros and functions to simply obtain
// Static storage enum variable to string.
// This version is much lighter on the compile times and is not restricted to the enum_range limitation.
NAMEOF_CONST_ENUM(Color::GREEN) -> "GREEN"
NAMEOF_ENUM_CONST(Color::GREEN) -> "GREEN"
nameof::nameof_enum<Color::GREEN>() -> "GREEN"
// Enum flags variable to string.
NAMEOF_ENUM_FLAG(Color::GREEN | Color::BLUE) -> "GREEN|BLUE"
nameof::nameof_enum_flag<Color::GREEN | Color::BLUE>() -> "GREEN|BLUE"
// Obtains name of enum variable or default value if enum variable out of range.
NAMEOF_ENUM_OR(Color::GREEN) -> "GREEN"
NAMEOF_ENUM_OR((Color)0, "none") -> "none"
```
* Nameof type
```cpp
using T = const int&;
T var = 42;
const my::detail::SomeClass<int>& var_ref = var;
// Name of variable type.
NAMEOF_TYPE_EXPR(var) -> "int"
NAMEOF_FULL_TYPE_EXPR(var) -> "const int&"
nameof::nameof_type<decltype(var)>() -> "int"
nameof::nameof_full_type<decltype(var)>() -> "const int&"
NAMEOF_TYPE_EXPR(var_ref) -> "my::detail::SomeClass<int>"
nameof::nameof_type<decltype(var_ref)>() -> "my::detail::SomeClass<int>"
NAMEOF_FULL_TYPE_EXPR(var_ref) -> "const my::detail::SomeClass<int>&"
nameof::nameof_full_type<decltype(var_ref)>() -> "const my::detail::SomeClass<int>&"
NAMEOF_SHORT_TYPE_EXPR(var_ref) -> "SomeClass"
nameof::nameof_short_type<decltype(var_ref)>() -> "SomeClass"
using T = const my::detail::SomeClass<int>&;
// Name of type.
NAMEOF_TYPE(T) -> "int"
NAMEOF_FULL_TYPE(T) -> "const int&"
nameof::nameof_type<T>() -> "int"
nameof::nameof_full_type<T>() -> "const int&"
NAMEOF_TYPE(T) ->"my::detail::SomeClass<int>"
nameof::nameof_type<T>() -> "my::detail::SomeClass<int>"
NAMEOF_FULL_TYPE(T) -> "const my::detail::SomeClass<int>&"
nameof::nameof_full_type<T>() -> "const my::detail::SomeClass<int>&"
NAMEOF_SHORT_TYPE(T) -> "SomeClass"
nameof::nameof_short_type<T>() -> "SomeClass"
my::detail::Base* ptr = new my::detail::Derived();
// Name of type, using rtti.
NAMEOF_TYPE_RTTI(*ptr) -> "my::detail::Derived"
NAMEOF_FULL_TYPE_RTTI(*ptr) -> "volatile const my::detail::Derived&"
NAMEOF_SHORT_TYPE_RTTI(*ptr) -> "Derived"
struct A {
int this_is_the_name;
};
// Obtains name of member.
NAMEOF_MEMBER(&A::this_is_the_name) -> "this_is_the_name"
nameof::nameof_member(&A::this_is_the_name) -> "this_is_the_name"
int someglobalvariable = 0;
// Obtains name of a function, a global or class static variable.
NAMEOF_POINTER(&someglobalconstvariable) == "someglobalconstvariable"
nameof::nameof_pointer(&someglobalconstvariable) == "someglobalconstvariable"
constexpr auto global_ptr = &someglobalvariable;
NAMEOF_POINTER(global_ptr) == "someglobalconstvariable"
nameof::nameof_pointer(global_ptr) == "someglobalconstvariable"
```
* Compile-time
```cpp
constexpr auto somevar_name = NAMEOF(somevar);
// somevar_name -> "somevar"
constexpr auto color_name = NAMEOF_ENUM(Color::BLUE); // or nameof::nameof_enum(Color::BLUE)
// color_name -> "BLUE"
constexpr auto var_type_name = NAMEOF_TYPE_EXPR(var); // or nameof::nameof_type<decltype(var)>()
// var_type_name -> "int"
constexpr auto type_name = NAMEOF_TYPE(T); // or nameof::nameof_type<T>()
// type_name -> "int"
```
## Remarks
* Before use, read the [limitations](doc/limitations.md) of functionality.
## Integration
@ -109,13 +124,22 @@ You should add required file [nameof.hpp](include/nameof.hpp).
If you are using [vcpkg](https://github.com/Microsoft/vcpkg/) on your project for external dependencies, then you can use the [nameof package](https://github.com/microsoft/vcpkg/tree/master/ports/nameof).
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `nameof/x.y.z@neargye/stable` to your conan's requires, where `x.y.z` is the release version you want to use.
If you are using [Conan](https://www.conan.io/) to manage your dependencies, merely add `nameof/x.y.z` to your conan's requires, where `x.y.z` is the release version you want to use.
Archlinux users can install `nameof` by package manager AUR, using the following command: `yay -S nameof`.
Alternatively, you can use something like [CPM](https://github.com/TheLartians/CPM) which is based on CMake's `Fetch_Content` module.
```cmake
CPMAddPackage(
NAME nameof
GITHUB_REPOSITORY Neargye/nameof
GIT_TAG x.y.z # Where `x.y.z` is the release version you want to use.
)
```
## Compiler compatibility
* Clang/LLVM >= 5
* MSVC++ >= 14.11 / Visual Studio >= 2017
* Xcode >= 10
* GCC >= 7 (GCC >= 9 for NAMEOF_ENUM)
Check in the [reference](doc/reference.md) for each features.
## Licensed under the [MIT License](LICENSE)

View file

@ -0,0 +1,239 @@
#[=======================================================================[.rst:
GenPkgConfig
------------
This is the library helping you to generate and install pkg-config files.
Unlicense
^^^^^^^^^
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this software, either in source code form or as a compiled binary, for any purpose, commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this software dedicate any and all copyright interest in the software to the public domain. We make this dedication for the benefit of the public at large and to the detriment of our heirs and successors. We intend this dedication to be an overt act of relinquishment in perpetuity of all present and future rights to this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org/>
Warning
^^^^^^^
CMake is currently merging a built-in impl of pkg-config file generator! https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6363
Functions
^^^^^^^^^
.. command:: configure_pkg_config_file
.. versionadded:: 3.22
Generates a pkg-config file for
::
configure_pkg_config_file(<targetName>
NAME <name of the package>
VERSION <version to be written into the package>
DESCRIPTION <description to be written into the package>
URL <homepage URL to be written into the package>
COMPONENT <install as the component>
INSTALL_LIB_DIR <path to something like CMAKE_INSTALL_LIBDIR>
INSTALL_INCLUDE_DIR <path to something like CMAKE_INSTALL_INCLUDEDIR>
REQUIRES ... <list of pkg-config packages this one depends on> ...
REQUIRES ... <list of pkg-config packages this one conflicts with> ...
)
The arguments are optional and usually are not needed to be set if global (not component-specific) CPACK vars have been set before.
Generation is done in build time using packaging expressions.
#]=======================================================================]
set("GEN_PKG_CONFIG_WORKAROUNDS_BUILD_TIME_SCRIPTS" "${CMAKE_CURRENT_LIST_DIR}/buildTimeScripts")
cmake_policy(SET CMP0070 NEW)
function(configure_pkg_config_file TARGET)
cmake_parse_arguments(""
"" # options
"NAME;VERSION;DESCRIPTION;URL;COMPONENT;INSTALL_LIB_DIR;INSTALL_INCLUDE_DIR" # one_value_keywords
"REQUIRES;CONFLICTS" # multi_value_keywords
${ARGN}
)
configure_pkg_config_file_vars("${TARGET}" "${_NAME}" "${_INSTALL_LIB_DIR}" "${_INSTALL_INCLUDE_DIR}" "${_COMPONENT}" "${_DESCRIPTION}" "${_URL}" "${_VERSION}" "${_REQUIRES}" "${_CONFLICTS}")
endfunction()
function(ge_expr_basename inputExpr outVar)
set("${outVar}" "$<TARGET_PROPERTY:${inputExpr}>" PARENT_SCOPE)
endfunction()
function(configure_pkg_config_file_vars TARGET _NAME _INSTALL_LIB_DIR _INSTALL_INCLUDE_DIR _COMPONENT _DESCRIPTION _URL _VERSION _REQUIRES _CONFLICTS)
#$<TARGET_PROPERTY:${TARGET},NAME>
#INTERFACE_LINK_DIRECTORIES
#INTERFACE_LINK_LIBRARIES
#INTERFACE_LINK_OPTIONS
if(_NAME)
else()
set(_NAME "$<TARGET_PROPERTY:${TARGET},NAME>")
endif()
if(_DESCRIPTION)
else()
set(_DESCRIPTION "${CPACK_PACKAGE_DESCRIPTION}")
endif()
if(_VERSION)
else()
set(_VERSION "${CPACK_PACKAGE_VERSION}")
endif()
if(_URL)
else()
set(_URL "${CPACK_PACKAGE_HOMEPAGE_URL}")
endif()
if(INSTALL_INCLUDE_DIR)
else()
set(INSTALL_INCLUDE_DIR "${CMAKE_INSTALL_INCLUDEDIR}")
endif()
if(INSTALL_LIB_DIR)
else()
set(INSTALL_LIB_DIR "${CMAKE_INSTALL_LIBDIR}")
endif()
set(PKG_CONFIG_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/${_NAME}.pc")
set(PUBLIC_INCLUDES "$<TARGET_PROPERTY:${TARGET},INTERFACE_INCLUDE_DIRECTORIES>")
set(PUBLIC_LIBS "$<TARGET_PROPERTY:${TARGET},INTERFACE_LINK_LIBRARIES>")
set(PUBLIC_COMPILE_FLAGS "$<TARGET_PROPERTY:${TARGET},INTERFACE_COMPILE_DEFINITIONS>")
set("IS_INTERFACE" "$<STREQUAL:$<TARGET_PROPERTY:${TARGET},TYPE>,INTERFACE_LIBRARY>")
set("IS_OBJECT" "$<STREQUAL:$<TARGET_PROPERTY:${TARGET},TYPE>,OBJECT_LIBRARY>")
get_target_property(CONFIGURE_TIME_TARGET_TYPE "${TARGET}" TYPE)
if(CONFIGURE_TIME_TARGET_TYPE STREQUAL OBJECT_LIBRARY)
set(CONFIGURE_TIME_IS_OBJECT ON) # Special measures have to be taken!!!
endif()
set("NEEDS_LIBS" "$<AND:$<NOT:${IS_INTERFACE}>,$<NOT:${IS_OBJECT}>>")
set("NEEDS_LIB_DIR" "$<NOT:${IS_INTERFACE}>")
string(REPLACE "," "$<COMMA>" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS}")
string(REPLACE ">" "$<ANGLE-R>" NEEDS_LIBS_ESCAPED "${NEEDS_LIBS_ESCAPED}")
list(APPEND header "prefix=${CMAKE_INSTALL_PREFIX}")
list(APPEND header "$<IF:$<OR:$<BOOL:${PUBLIC_LIBS}>,${NEEDS_LIB_DIR}>,libdir=\${prefix}/${INSTALL_LIB_DIR},>")
list(APPEND header "$<IF:$<BOOL:${PUBLIC_INCLUDES}>,includedir=\${prefix}/${INSTALL_INCLUDE_DIR},>")
list(APPEND libSpecific "Name: ${_NAME}")
if(_DESCRIPTION)
list(APPEND libSpecific "Description: ${_DESCRIPTION}")
endif()
if(_URL)
list(APPEND libSpecific "URL: ${_URL}")
endif()
if(_VERSION)
list(APPEND libSpecific "Version: ${_VERSION}")
endif()
if(_REQUIRES)
list(APPEND libSpecific "Requires: ${_REQUIRES}")
endif()
if(_CONFLICTS)
list(APPEND libSpecific "Conflicts: ${_CONFLICTS}")
endif()
set(OTHER_INCLUDE_FLAGS "-I$<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_INCLUDES}>, -I>") # Not needed, we can only get build interface flags here. Insert them after -I\${includedir} if you find a way to fix/workaround it
# Here is a workaround to inability to use TARGET_LINKER_FILE_NAME for targets not involving library generation.
# Strangely $<IF evaluates both branches, not only the one taken, which causes an error
# We workaround it by generating the subexpression source using $<IF and then evaluating it using $<GENEX_EVAL
# Of course we could have used conditional expressions on CMake script part, but I have decided to implement it in generator expressions part, so hypthetically all the expressions can be merged into a single file and this function can be made simple
set(ESCAPED_GENEXPR_BEGINNING "$<1:$><") # A hack because there is no escape for `$` or `<` or `$<`. So we just disrupt $< into pieces
set(CURRENT_LIB_ESCAPED_BINARY_NAME "${ESCAPED_GENEXPR_BEGINNING}TARGET_LINKER_FILE_NAME:${TARGET}$<ANGLE-R>")
set(LINK_CURRENT_LIB_FLAG "$<GENEX_EVAL:$<IF:${NEEDS_LIBS},-l:${CURRENT_LIB_ESCAPED_BINARY_NAME},>>")
if(CONFIGURE_TIME_IS_OBJECT)
set(IS_TARGET_OBJECTS_CONFIGURE_TIME_UNAVAILABLE ON)
if(IS_TARGET_OBJECTS_CONFIGURE_TIME_UNAVAILABLE)
message(WARNING "CMake is shit: There is (at least was at the time of writing of this code) no generator expression to get only basenames of object files. They are also unavailable at configure stage. And there were no CMake generator expressions for making replacements in strings. So we workaround this.")
set(TARGET_OBJECTS_FILE "${TARGET}.obj_list")
set(OBJECTS_FILE_RETRIEVAL_TARGET_NAME "${TARGET}_get_objects_list")
set(PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME "${TARGET}_pkgconfig_unfinished")
set(PKGCONFIG_PATCH_TARGET_NAME "${TARGET}_patch_pkgconfig")
set(PKG_CONFIG_FILE_NAME_FINISHED "${PKG_CONFIG_FILE_NAME}")
set(PKG_CONFIG_FILE_NAME_UNFINISHED "${PKG_CONFIG_FILE_NAME_FINISHED}.unfinished")
file(GENERATE OUTPUT "${TARGET_OBJECTS_FILE}" CONTENT "$<TARGET_OBJECTS:${TARGET}>")
add_custom_command(
OUTPUT "${TARGET_OBJECTS_FILE}"
COMMENT "A dummy command to workaround cmake limitations"
)
add_custom_target("${OBJECTS_FILE_RETRIEVAL_TARGET_NAME}"
DEPENDS "${TARGET_OBJECTS_FILE}"
)
add_custom_command(
OUTPUT "${PKG_CONFIG_FILE_NAME_FINISHED}"
PRE_BUILD COMMAND ${CMAKE_COMMAND} "-DobjectsFile=\"${TARGET_OBJECTS_FILE}\"" "-DpkgConfigFileUnlinished=\"${PKG_CONFIG_FILE_NAME_UNFINISHED}\"" "-DpkgConfigFileFinal=\"${PKG_CONFIG_FILE_NAME_FINISHED}\"" "-P" "${GEN_PKG_CONFIG_WORKAROUNDS_BUILD_TIME_SCRIPTS}/getObjectFilesBaseNames.cmake"
MAIN_DEPENDENCY "${TARGET_OBJECTS_FILE}"
DEPENDS "${PKG_CONFIG_FILE_NAME_UNFINISHED}"
COMMENT "Working around CMake limitations about getting list of basenames of object files and about lack of generator expressions to modify strings: ${PKG_CONFIG_FILE_NAME_UNFINISHED} + ${TARGET_OBJECTS_FILE} -> ${PKG_CONFIG_FILE_NAME_FINISHED}"
)
add_custom_target("${PKGCONFIG_PATCH_TARGET_NAME}" ALL
DEPENDS "${PKG_CONFIG_FILE_NAME_FINISHED}"
)
add_dependencies("${PKGCONFIG_PATCH_TARGET_NAME}" "${OBJECTS_FILE_RETRIEVAL_TARGET_NAME}" "${PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME}")
set(PROPERLY_JOINED_TARGET_OBJECTS "@PROPERLY_JOINED_TARGET_OBJECTS@")
else()
set("RAW_TARGET_OBJECTS" "$<TARGET_OBJECTS:${TARGET}>")
message(FATAL_ERROR "This branch is unimplemented because CMake lacked the needed functionality at the time")
set(PROPERLY_JOINED_TARGET_OBJECTS "${RAW_TARGET_OBJECTS}")
endif()
endif()
set(LINK_CURRENT_OBJECT_FLAG "$<IF:${IS_OBJECT},${PROPERLY_JOINED_TARGET_OBJECTS},>")
list(APPEND libSpecific "$<IF:$<OR:$<BOOL:${PUBLIC_LIBS}>,${NEEDS_LIBS},${IS_OBJECT}>,Libs: -L\${libdir} ${LINK_CURRENT_LIB_FLAG} ${LINK_CURRENT_OBJECT_FLAG} $<IF:$<BOOL:${PUBLIC_LIBS}>,-l$<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_LIBS}>, -l>,>,>\n$<IF:$<OR:$<BOOL:${PUBLIC_INCLUDES}>,$<BOOL:${PUBLIC_COMPILE_FLAGS}>>,Cflags: -I\${includedir} $<JOIN:$<REMOVE_DUPLICATES:${PUBLIC_COMPILE_FLAGS}>,>,>")
list(JOIN header "\n" header)
list(JOIN libSpecific "\n" libSpecific)
set(libSpecific "${header}\n\n${libSpecific}")
if(CONFIGURE_TIME_IS_OBJECT)
file(GENERATE OUTPUT "${PKG_CONFIG_FILE_NAME_UNFINISHED}"
CONTENT "${libSpecific}"
)
# Dummy target for generated files
add_custom_command(
OUTPUT "${PKG_CONFIG_FILE_NAME_UNFINISHED}"
COMMENT "A dummy command to workaround cmake limitations"
)
add_custom_target("${PKGCONFIG_DUMMY_UNFINISHED_GEN_TARGET_NAME}"
DEPENDS "${PKG_CONFIG_FILE_NAME_UNFINISHED}"
)
install(FILES "${PKG_CONFIG_FILE_NAME_FINISHED}"
DESTINATION "${_INSTALL_LIB_DIR}/pkgconfig"
COMPONENT "${_COMPONENT}"
)
else()
file(GENERATE OUTPUT "${PKG_CONFIG_FILE_NAME}"
CONTENT "${libSpecific}"
)
install(FILES "${PKG_CONFIG_FILE_NAME}"
DESTINATION "${_INSTALL_LIB_DIR}/pkgconfig"
COMPONENT "${_COMPONENT}"
)
endif()
endfunction()

View file

@ -0,0 +1,45 @@
GenPkgConfig.cmake
===================
A script generating pkg-config files.
WARNING: CMake [is currently merging own built-in pkgconfig generation implementation](https://gitlab.kitware.com/cmake/cmake/-/merge_requests/6363)!
If you require such a new version of CMake, you probably should use the built-in impl instead.
Syntax
------
```cmake
configure_pkg_config_file(<targetName>
NAME <name of the pkgconfig package>
VERSION <version to be written into the package>
DESCRIPTION <description to be written into the package>
URL <homepage URL to be written into the package>
COMPONENT <install as the component>
INSTALL_LIB_DIR <path to something like CMAKE_INSTALL_LIBDIR>
INSTALL_INCLUDE_DIR <path to something like CMAKE_INSTALL_INCLUDEDIR>
REQUIRES ... <list of pkg-config packages this one depends on> ...
REQUIRES ... <list of pkg-config packages this one conflicts with> ...
)
```
Issuees
-------
1. For `OBJECT` targets we have run into big issues. CMake
1. Doesn't allow to get the list of object files at configure time
2. Allows to get a list of object files as a generator exression ...
3. BUT ... the path to them is full, but we need only file name!
4. CMake doesn't allow to strip directory path via generator expression
5. ... neither it allows string editing within generator expressions ...
so ... we have to create a custom target using a custom CMake script executed separately, but ...
6. `file(GENERATE` doesn't properly register dependencies
... so we have to use `add_custom_command` to say CMake that these files are generated
7. And CMake `install(FILES` doesn't mean that the targets generating these files are automatically executed,
So we have to use `ALL` in `add_custom_target`.

View file

@ -0,0 +1,24 @@
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or
distribute this software, either in source code form or as a compiled
binary, for any purpose, commercial or non-commercial, and by any
means.
In jurisdictions that recognize copyright laws, the author or authors
of this software dedicate any and all copyright interest in the
software to the public domain. We make this dedication for the benefit
of the public at large and to the detriment of our heirs and
successors. We intend this dedication to be an overt act of
relinquishment in perpetuity of all present and future rights to this
software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
For more information, please refer to <https://unlicense.org/>

View file

@ -0,0 +1,18 @@
message(STATUS "objectsFile ${objectsFile}")
message(STATUS "pkgConfigFileFinal ${pkgConfigFileFinal}")
message(STATUS "pkgConfigFileUnlinished ${pkgConfigFileUnlinished}")
file(READ "${objectsFile}" TARGET_OBJECTS)
set(PROPERLY_JOINED_TARGET_OBJECTS "")
foreach(objFullPath ${TARGET_OBJECTS})
get_filename_component(objFullPath "${objFullPath}" NAME)
list(APPEND PROPERLY_JOINED_TARGET_OBJECTS "${objFullPath}")
endforeach()
list(JOIN PROPERLY_JOINED_TARGET_OBJECTS " " PROPERLY_JOINED_TARGET_OBJECTS)
message(STATUS "PROPERLY_JOINED_TARGET_OBJECTS AFTER ${PROPERLY_JOINED_TARGET_OBJECTS}")
configure_file("${pkgConfigFileUnlinished}" "${pkgConfigFileFinal}" @ONLY)

View file

@ -1,52 +0,0 @@
# -*- coding: utf-8 -*-
from conans import ConanFile
from conans.errors import ConanInvalidConfiguration
class NameofConan(ConanFile):
name = "nameof"
version = "0.9.3"
description = "Header-only C++17 library provides nameof macros and functions to simply obtain the name of a variable, type, function, macro, and enum."
topics = (
"conan",
"nameof",
"cplusplus",
"enum-to-string",
"serialization",
"reflection",
"header-only",
"compile-time"
)
url = "https://github.com/Neargye/nameof"
homepage = "https://github.com/Neargye/nameof"
author = "Daniil Goncharov <neargye@gmail.com>"
license = "MIT"
exports_sources = ["include/*", "LICENCE"]
exports = ["LICENSE"]
settings = "compiler"
no_copy_source = True
@property
def supported_compiler(self):
compiler = str(self.settings.compiler)
version = str(self.settings.compiler.version)
if compiler == "Visual Studio" and version >= "15":
return True
if compiler == "gcc" and version >= "7":
return True
if compiler == "clang" and version >= "5":
return True
if compiler == "apple-clang" and version >= "9":
return True
return False
def configure(self):
if not self.supported_compiler:
raise ConanInvalidConfiguration("nameof: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).")
def package(self):
self.copy("include/*")
self.copy("LICENSE", dst="licenses")
def package_id(self):
self.info.header_only()

View file

@ -1,84 +1,68 @@
# Nameof
# Limitations
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
## Nameof
# Nameof Type
* If the argument does not have a name, the compilation error `"Expression does not have a name."` occurs.
* To check is nameof type supported compiler use macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.
## Nameof Type
* This library uses a compiler-specific hack (based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`), which works on Clang >= 5, MSVC >= 15.3 and GCC >= 7.
* This library uses a compiler-specific hack (based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`).
* Nameof type returns compiler-specific type name.
* nameof_type and nameof_type_rtti return a compiler-specific type name.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* To check if nameof_type is supported by your compiler use the macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.</br>
If nameof_type is used on an unsupported compiler, a compilation error occurs. To suppress the error define the macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
# Nameof Enum
* To check if nameof_type_rtti is supported by your compiler use macro `NAMEOF_TYPE_RTTI_SUPPORTED` or constexpr constant `nameof::is_nameof_type_rtti_supported`.</br>
If nameof_type_rtti is used on an unsupported compiler, a compilation error occurs. To suppress the error define the macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
* To check is nameof enum supported compiler use macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.
* To check is nameof_member supported compiler use macro `NAMEOF_MEMBER_SUPPORTED` or constexpr constant `nameof::is_nameof_member_supported`.</br>
If nameof_member used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
* To check is nameof_pointer supported compiler use macro `NAMEOF_POINTER_SUPPORTED` or constexpr constant `nameof::is_nameof_pointer_supported`.</br>
If nameof_pointer used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
## Nameof Enum
* This library uses a compiler-specific hack (based on `__PRETTY_FUNCTION__` / `__FUNCSIG__`), which works on Clang >= 5, MSVC >= 15.3 and GCC >= 9.
* Enum can't reflect if the enum is a forward declaration.
* Do not use [nameof](https://github.com/Neargye/nameof) and [magic_enum](https://github.com/Neargye/magic_enum) in the same project to get enum name.
* Enum value must be in range `[NAMEOF_ENUM_RANGE_MIN, NAMEOF_ENUM_RANGE_MAX]`. By default `NAMEOF_ENUM_RANGE_MIN = -128`, `NAMEOF_ENUM_RANGE_MAX = 128`.
* To check if nameof_enum is supported by your compiler use the macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.</br>
If nameof_enum is used on an unsupported compiler, a compilation error occurs. To suppress the error define the macro `NAMEOF_ENUM_NO_CHECK_SUPPORT`.
* If need another range for all enum types by default, redefine the macro `NAMEOF_ENUM_RANGE_MIN` and `NAMEOF_ENUM_RANGE_MAX`.
```cpp
#define NAMEOF_ENUM_RANGE_MIN 0
#define NAMEOF_ENUM_RANGE_MAX 256
#include <nameof.hpp>
```
* Enum value must be in range `[NAMEOF_ENUM_RANGE_MIN, NAMEOF_ENUM_RANGE_MAX]`.
* If need another range for specific enum type, add specialization `enum_range` for necessary enum type.
```cpp
#include <nameof.hpp>
* By default `NAMEOF_ENUM_RANGE_MIN = -128`, `NAMEOF_ENUM_RANGE_MAX = 128`.
enum number { one = 100, two = 200, three = 300 };
* `NAMEOF_ENUM_RANGE_MIN` must be less than or equal to `0` and must be greater than `INT16_MIN`.
namespace nameof {
template <>
struct enum_range<number> {
static constexpr int min = 100;
static constexpr int max = 300;
};
}
```
* `NAMEOF_ENUM_RANGE_MAX` must be greater than `0` and must be less than `INT16_MAX`.
* Nameof enum obtains the first defined value enums, and won't work if value are aliased.
```cpp
enum ShapeKind {
ConvexBegin = 0,
Box = 0, // Won't work.
Sphere = 1,
ConvexEnd = 2,
Donut = 2, // Won't work too.
Banana = 3,
COUNT = 4,
};
// nameof::nameof_enum(ShapeKind::Box) -> "ConvexBegin"
// NAMEOF_ENUM(ShapeKind::Box) -> "ConvexBegin"
```
Work around the issue:
```cpp
enum ShapeKind {
// Convex shapes, see ConvexBegin and ConvexEnd below.
Box = 0,
Sphere = 1,
* If another range is needed for all enum types by default, redefine the macro `NAMEOF_ENUM_RANGE_MIN` and `NAMEOF_ENUM_RANGE_MAX`.
// Non-convex shapes.
Donut = 2,
Banana = 3,
```cpp
#define NAMEOF_ENUM_RANGE_MIN 0
#define NAMEOF_ENUM_RANGE_MAX 256
#include <nameof.hpp>
```
COUNT = Banana + 1,
* If another range is needed for a specific enum type, add specialization `enum_range` for necessary enum type. Specialization of `enum_range` must be injected in `namespace nameof::customize`.
// Non-reflected aliases.
ConvexBegin = Box,
ConvexEnd = Sphere + 1,
};
// nameof::nameof_enum(ShapeKind::Box) -> "Box"
// NAMEOF_ENUM(ShapeKind::Box) -> "Box"
```cpp
#include <nameof.hpp>
// Non-reflected aliases.
// nameof::nameof_enum(ShapeKind::ConvexBegin) -> "Box"
// NAMEOF_ENUM(ShapeKind::ConvexBegin) -> "Box"
```
enum class number { one = 100, two = 200, three = 300 };
template <>
struct nameof::customize::enum_range<number> {
static constexpr int min = 100;
static constexpr int max = 300;
};
```
* Won't work if a value is aliased, support for enum-aliases is compiler-implementation-defined.
* Won't work if the enum is a forward declaration.
* Intellisense Visual Studio may have some problems analyzing `nameof`.

View file

@ -1,40 +1,65 @@
# Reference
* [`NAMEOF` macro that obtains simple (unqualified) string name of variable, function, macro.](#NAMEOF)
* [`NAMEOF_FULL` macro that obtains simple (unqualified) full (with template suffix) string name of variable, function, macro.](#NAMEOF_FULL)
* [`NAMEOF_RAW` macro that obtains raw string name of variable, function, macro.](#NAMEOF_RAW)
* [`nameof_enum(E value)` function that obtains simple (unqualified) string enum name of enum variable.](#nameof_enum(value))
* [`nameof_enum<auto V>()` function that obtains simple (unqualified) string enum name of static storage enum variable.](#nameof_enum<Value>())
* [`NAMEOF_ENUM` macro that obtains simple (unqualified) string enum name of enum variable.](#NAMEOF_ENUM)
* [`NAMEOF_CONST_ENUM` macro that obtains simple (unqualified) string enum name of static storage enum variable.](#NAMEOF_CONST_ENUM)
* [`nameof_type<T>()` function that obtains string name of type, reference and cv-qualifiers are ignored.](#nameof_type<T>())
* [`nameof_full_type<T>()` function that obtains string name of full type, with reference and cv-qualifiers.](#nameof_full_type<T>())
* [`NAMEOF_TYPE` macro that obtains string name of type, reference and cv-qualifiers are ignored.](#NAMEOF_TYPE)
* [`NAMEOF_FULL_TYPE` macro that obtains string name of full type, with reference and cv-qualifiers.](#NAMEOF_FULL_TYPE)
* [`NAMEOF_TYPE_EXPR` macro that obtains string name type of expression, reference and cv-qualifiers are ignored.](#NAMEOF_TYPE_EXPR)
* [`NAMEOF_FULL_TYPE_EXPR` macro that obtains string name full type of expression, with reference and cv-qualifiers.](#NAMEOF_FULL_TYPE_EXPR)
* [`NAMEOF` obtains simple name of variable, function, macro.](#nameof)
* [`NAMEOF_FULL` obtains full name of variable, function, macro.](#nameof_full)
* [`NAMEOF_RAW` obtains raw name of variable, function, macro.](#nameof_raw)
* [`NAMEOF_ENUM` obtains name of enum variable.](#nameof_enum)
* [`NAMEOF_ENUM_OR` Obtains name of enum variable or default value if enum variable out of range.](#nameof_enum_or)
* [`NAMEOF_ENUM_CONST` obtains name of static storage enum variable.](#nameof_enum_const)
* [`NAMEOF_ENUM_FLAG` obtains name of enum-flags variable.](#nameof_enum_flag)
* [`NAMEOF_TYPE` obtains type name.](#nameof_type)
* [`NAMEOF_FULL_TYPE` obtains full type name.](#nameof_full_type)
* [`NAMEOF_SHORT_TYPE` obtains short type name.](#nameof_short_type)
* [`NAMEOF_TYPE_EXPR` obtains type name of expression.](#nameof_type_expr)
* [`NAMEOF_FULL_TYPE_EXPR` obtains full type name of expression.](#nameof_full_type_expr)
* [`NAMEOF_SHORT_TYPE_EXPR` obtains short type name of expression.](#nameof_short_type_expr)
* [`NAMEOF_TYPE_RTTI` obtains type name, using RTTI.](#nameof_type_rtti)
* [`NAMEOF_FULL_TYPE_RTTI` obtains short type name, using RTTI.](#nameof_full_type_rtti)
* [`NAMEOF_SHORT_TYPE_RTTI` obtains short type name, using RTTI.](#nameof_short_type_rtti)
* [`NAMEOF_MEMBER` obtains name of member.](#nameof_member)
* [`NAMEOF_POINTER` obtains name of a function, a global or class static variable.](#nameof_pointer)
# Synopsis
## Synopsis
* Before use, read the [limitations](limitations.md) of functionality.
* All functions `constexpr` and `noexcept`.
* To check is nameof_enum supported compiler use macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.</br>
If nameof_enum used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_ENUM_NO_CHECK_SUPPORT`.
* To check is nameof_type supported compiler use macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
* To check is nameof_type supported compiler use macro `NAMEOF_TYPE_SUPPORTED` or constexpr constant `nameof::is_nameof_type_supported`.</br>
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
* To check is nameof_enum supported compiler use macro `NAMEOF_ENUM_SUPPORTED` or constexpr constant `nameof::is_nameof_enum_supported`.
If nameof_enum used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_ENUM_NO_CHECK_SUPPORT`.
* To check is nameof_type_rtti supported compiler use macro `NAMEOF_TYPE_RTTI_SUPPORTED` or constexpr constant `nameof::is_nameof_type_rtti_supported`.</br>
If nameof_type used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
* To check is nameof_member supported compiler use macro `NAMEOF_MEMBER_SUPPORTED` or constexpr constant `nameof::is_nameof_member_supported`.</br>
If nameof_member used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
* To check is nameof_pointer supported compiler use macro `NAMEOF_POINTER_SUPPORTED` or constexpr constant `nameof::is_nameof_pointer_supported`.</br>
If nameof_pointer used on unsupported compiler, occurs the compilation error. To suppress error define macro `NAMEOF_TYPE_NO_CHECK_SUPPORT`.
* To add custom enum or type names see the [example](../example/example_custom_name.cpp).
* To change the type of strings, use special macros:
```cpp
#include <my_lib/string.hpp>
#include <my_lib/string_view.hpp>
#define NAMEOF_USING_ALIAS_STRING using string = my_lib::String;
#define NAMEOF_USING_ALIAS_STRING_VIEW using string_view = my_lib::StringView;
#include <nameof.hpp>
```
## `NAMEOF`
* Macro that obtains simple (unqualified) string name of variable, function, macro.
* Obtains name of variable, function, macro.
* Returns `nameof::cstring` - constexpr implementation of an string.
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* Examples
```cpp
// Name of variable.
NAMEOF(somevar) -> "somevar"
@ -54,15 +79,21 @@ If nameof_enum used on unsupported compiler, occurs the compilation error. To su
NAMEOF(NAMEOF(structvar)) -> "NAMEOF"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_FULL`
* Macro that obtains simple (unqualified) full (with template suffix) string name of variable, function, macro.
* Obtains full (with template suffix) name of variable, function, macro.
* Returns `nameof::cstring` - constexpr implementation of an string.
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* Examples
```cpp
// Full name of template function.
NAMEOF_FULL(foo<int, float>()) -> "foo<int, float>"
@ -71,178 +102,361 @@ If nameof_enum used on unsupported compiler, occurs the compilation error. To su
NAMEOF_FULL(somevar.some_method<int>()) -> "some_method<int>"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_RAW`
* Macro that obtains raw string name of variable, function, macro.
* Obtains raw name of variable, function, macro.
* Returns `nameof::cstring` - constexpr implementation of an string.
* Returns `nameof::cstring` - constexpr implementation of an string. Marked `constexpr` and `noexcept`.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* Examples
```cpp
NAMEOF_RAW(::somevar.somefield) -> "::somevar.somefield"
NAMEOF_RAW(&some_class::some_method<int>) -> "&some_class::some_method<int>"
```
## `nameof_enum(value)`
* Function that obtains simple (unqualified) string enum name of enum variable.
* Returns `std::string_view`.
* If argument does not have name, returns empty `std::string_view`.
* Examples
```cpp
auto color = Color::RED;
nameof::nameof_enum(color) -> "RED"
```
## `nameof_enum<Value>()`
* Function that obtains simple (unqualified) string enum name of static storage enum variable.
* Returns `std::string_view`.
* This version is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md).
* If argument does not have name, returns empty `std::string_view`.
* Examples
```cpp
nameof::nameof_enum<Color::GREEN>() -> "GREEN"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_ENUM`
* Macro that obtains simple (unqualified) string enum name of enum variable.
* Obtains name of enum variable.
* Returns `std::string_view`.
* Returns `string_view`. Marked `constexpr` and `noexcept`.
* If argument does not have name, returns empty `std::string_view`.
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `string_view`, in debug occurs assert.
* Examples
```cpp
auto color = Color::RED;
NAMEOF_ENUM(color) -> "RED"
nameof::nameof_enum(color) -> "RED"
```
## `NAMEOF_CONST_ENUM`
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 9 and C++ >= 17</br>
* Macro macro that obtains simple (unqualified) string enum name of static storage enum variable.
# `NAMEOF_ENUM_OR`
* Returns `std::string_view`.
* Obtains name of enum variable or default value if enum variable out of range.
* This version is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md).
* Returns `string`.
* If argument does not have name, returns empty `std::string_view`.
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns `default_value`.
```cpp
auto color = Color::RED;
NAMEOF_ENUM_OR(color, "none") -> "RED"
NAMEOF_ENUM_OR((Color)-1, "none") -> "none"
nameof::nameof_enum_or(color, "none") -> "RED"
nameof::nameof_enum_or((Color)-1, "none") -> "none"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 9 and C++ >= 17</br>
## `NAMEOF_ENUM_CONST`
* Obtains name of static storage enum variable.
* Returns `string_view`. Marked `constexpr` and `noexcept`.
* This version is much lighter on the compile times and is not restricted to the enum_range [limitation](limitations.md#nameof-enum).
* If argument does not have name, occurs the compilation error `"Enum value does not have a name."`.
* Examples
```cpp
NAMEOF_CONST_ENUM(Color::GREEN) -> "GREEN"
NAMEOF_ENUM_CONST(Color::GREEN) -> "GREEN"
nameof::nameof_enum<Color::GREEN>() -> "GREEN"
```
## `nameof_type<T>()`
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 9 and C++ >= 17</br>
* Function macro that obtains string name of type, reference and cv-qualifiers are ignored.
## `NAMEOF_ENUM_FLAG`
* Returns `nameof::cstring` - constexpr implementation of an string.
* Obtains name of enum flag variable.
* In all cases, reference and cv-qualifiers are ignored by `nameof_type` (that is, `nameof_type<const T&>() == nameof_type<T>()`).
* Returns `string`.
* Returns compiler-specific type name.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* If argument does not have name or [out of range](limitations.md#nameof-enum), returns empty `string`, in debug occurs assert.
* Examples
```cpp
using T = const int&;
nameof::nameof_type<T>() -> "int"
enum class AnimalFlags { HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 };
auto flag = AnimalFlags::Endangered;
NAMEOF_ENUM_FLAG(flag) -> "Endangered"
nameof_enum_flag(flag) -> "Endangered"
flag = AnimalFlags::CanFly | AnimalFlags::Endangered;
NAMEOF_ENUM_FLAG(flag) -> "CanFly|Endangered"
nameof_enum_flag(flag) -> "CanFly|Endangered"
nameof_enum_flag(flag, '$') -> "CanFly$Endangered"
NAMEOF_ENUM(HasClaws | CanFly) -> ""
nameof_enum(HasClaws | CanFly) -> ""
```
## `nameof_full_type<T>()`
* Function that obtains string name of full type, with reference and cv-qualifiers.
* Returns `nameof::cstring` - constexpr implementation of an string.
* Returns compiler-specific type name.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* Examples
```cpp
using T = const int&;
nameof::nameof_full_type<T>() -> "const int&"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 9 and C++ >= 17</br>
## `NAMEOF_TYPE`
* Macro macro that obtains string name of type, reference and cv-qualifiers are ignored.
* Obtains type name, reference and cv-qualifiers are ignored.
* Returns `nameof::cstring` - constexpr implementation of an string.
* Returns `string_view`. Marked `constexpr` and `noexcept`.
* In all cases, reference and cv-qualifiers are ignored by `NAMEOF_TYPE` (that is, `NAMEOF_TYPE(const T&) == NAMEOF_TYPE(T)`).
* Returns compiler-specific type name.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
* Examples
```cpp
using T = const int&;
NAMEOF_TYPE(T) -> "int"
nameof::nameof_type<T>() -> "int"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_FULL_TYPE`
* Macro that obtains string name of full type, with reference and cv-qualifiers.
* Obtains full type name, with reference and cv-qualifiers.
* Returns `nameof::cstring` - constexpr implementation of an string.
* Returns `string_view`. Marked `constexpr` and `noexcept`.
* Returns compiler-specific type name.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
* Examples
```cpp
using T = const int&;
NAMEOF_TYPE(T) -> "const int&"
nameof::nameof_full_type<T>() -> "const int&"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_SHORT_TYPE`
* Obtains short type name.
* Returns `string_view`. Marked `constexpr` and `noexcept`.
* Returns compiler-specific type name.
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
* Examples
```cpp
using T = const my::detail::SomeClass<int>&;
NAMEOF_SHORT_TYPE(T) -> "SomeClass"
nameof::nameof_short_type<T>() -> "SomeClass"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_TYPE_EXPR`
* Macro that obtains string name type of expression, reference and cv-qualifiers are ignored.
* Obtains string name type of expression, reference and cv-qualifiers are ignored.
* Returns `nameof::cstring` - constexpr implementation of an string.
* Returns `string_view`. Marked `constexpr` and `noexcept`.
* Returns returns compiler-specific type name.
* Returns compiler-specific type name.
* In all cases, reference and cv-qualifiers are ignored.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
* Examples
```cpp
using T = const int&;
T var = 42;
NAMEOF_TYPE_EXPR(var) -> "int"
nameof::nameof_type<decltype(var)>() -> "int"
```
## `NAMEOF_TYPE_EXPR`
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
* Macro that obtains string name full type of expression, with reference and cv-qualifiers.
## `NAMEOF_FULL_TYPE_EXPR`
* Returns `nameof::cstring` - constexpr implementation of an string.
* Obtains full type name of expression, with reference and cv-qualifiers.
* Returns `string_view`. Marked `constexpr` and `noexcept`.
* Returns compiler-specific type name.
* If argument does not have name, occurs the compilation error `"Expression does not have a name."`.
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
* Examples
```cpp
using T = const int&;
T var = 42;
NAMEOF_FULL_TYPE_EXPR(var) -> "const int&"
nameof::nameof_full_type<decltype(var)>() -> "const int&"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_SHORT_TYPE_EXPR`
* Obtains short type name of expression.
* Returns `string_view`. Marked `constexpr` and `noexcept`.
* Returns compiler-specific type name.
* If type does not have name, occurs the compilation error `"Type does not have a name."`.
* Examples
```cpp
const my::detail::SomeClass<int> var;
NAMEOF_SHORT_TYPE_EXPR(var) -> "SomeClass"
nameof::nameof_short_type<decltype(var)>() -> "SomeClass"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2017 and C++ >= 17</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_TYPE_RTTI`
* Obtains type name, using RTTI.
* Returns `string`.
* Examples
```cpp
volatile const my::detail::Base* ptr = new my::detail::Derived();
NAMEOF_TYPE_RTTI(*ptr) -> "my::detail::Derived"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17 and RTTI enabled</br>
Visual Studio >= 2017 and C++ >= 17 and RTTI enabled</br>
GCC >= 7 and C++ >= 17 and RTTI enabled</br>
## `NAMEOF_FULL_TYPE_RTTI`
* Obtains full type name, using RTTI.
* Returns `string`.
* Examples
```cpp
volatile const my::detail::Base* ptr = new my::detail::Derived();
NAMEOF_FULL_TYPE_RTTI(cv_ref) -> "volatile const my::detail::Derived&"
``
## `NAMEOF_SHORT_TYPE_RTTI`
* Obtains short type name, using RTTI.
* Returns `string`.
* Examples
```cpp
volatile const my::detail::Base* ptr = new my::detail::Derived();
NAMEOF_SHORT_TYPE_RTTI(*ptr) -> "Derived"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17 and RTTI enabled</br>
Visual Studio >= 2017 and C++ >= 17 and RTTI enabled</br>
GCC >= 7 and C++ >= 17 and RTTI enabled</br>
## `NAMEOF_MEMBER`
* Obtains name of member.
* Returns `string_view`.
* Examples
```cpp
struct A {
int this_is_the_name;
};
// ..
NAMEOF_MEMBER(&A::this_is_the_name) -> "this_is_the_name"
nameof::nameof_member(&A::this_is_the_name) -> "this_is_the_name"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2022 and C++ >= 20</br>
GCC >= 7 and C++ >= 17</br>
## `NAMEOF_POINTER`
* Obtains name of a function, a global or class static variable.
* Returns `string_view`.
* Examples
```cpp
int someglobalvariable = 0;
// ..
NAMEOF_POINTER(&someglobalconstvariable) == "someglobalconstvariable"
nameof::nameof_pointer(&someglobalconstvariable) == "someglobalconstvariable"
constexpr auto global_ptr = &someglobalvariable;
NAMEOF_POINTER(global_ptr) == "someglobalconstvariable"
nameof::nameof_pointer(global_ptr) == "someglobalconstvariable"
```
* Compiler compatibility
Clang/LLVM >= 5 and C++ >= 17</br>
Visual Studio >= 2022 and C++ >= 20</br>
GCC >= 7 and C++ >= 17</br>

View file

@ -9,8 +9,15 @@ elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
endif()
endif()
add_executable(example example.cpp)
set_target_properties(example PROPERTIES CXX_EXTENSIONS OFF)
target_compile_features(example PRIVATE cxx_std_17)
target_compile_options(example PRIVATE ${OPTIONS})
target_link_libraries(example PRIVATE ${CMAKE_PROJECT_NAME})
function(make_example target)
add_executable(${target} ${target}.cpp)
set_target_properties(${target} PROPERTIES CXX_EXTENSIONS OFF)
target_compile_options(${target} PRIVATE ${OPTIONS})
target_link_libraries(${target} PRIVATE ${CMAKE_PROJECT_NAME})
endfunction()
make_example(example)
make_example(example_custom_name)
if(NAMEOF_MODULE)
make_example(example_module)
endif()

View file

@ -1,6 +1,6 @@
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
// Copyright (c) 2018 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -27,6 +27,10 @@
#include <sstream>
#include <stdexcept>
struct Base { virtual ~Base() = default; };
struct Derived : Base {};
struct SomeStruct {
int somefield = 0;
@ -79,6 +83,8 @@ struct Long {
enum class Color { RED, GREEN, BLUE };
enum AnimalFlags { HasClaws = 1 << 0, CanFly = 1 << 1, EatsFish = 1 << 2, Endangered = 1 << 3 };
SomeStruct structvar;
Long othervar;
SomeStruct* ptrvar = &structvar;
@ -120,6 +126,11 @@ int main() {
std::cout << nameof::nameof_enum(color) << std::endl; // 'RED'
std::cout << NAMEOF_ENUM(color) << std::endl; // 'RED'
std::cout << nameof::nameof_enum<Color::GREEN>() << std::endl; // 'GREEN'
// Nameof enum flags.
auto flag = static_cast<AnimalFlags>(AnimalFlags::CanFly | AnimalFlags::EatsFish);
std::cout << nameof::nameof_enum_flag(flag) << std::endl; // 'CanFly|EatsFish'
std::cout << NAMEOF_ENUM_FLAG(flag) << std::endl; // 'CanFly|EatsFish'
#endif
// Nameof.
@ -147,12 +158,24 @@ int main() {
std::cout << NAMEOF_TYPE(const Long::LL&) << std::endl; // 'Long::LL'
std::cout << nameof::nameof_full_type<const Long::LL&>() << std::endl; // 'const Long::LL &'
std::cout << NAMEOF_FULL_TYPE(const Long::LL&) << std::endl; // 'const Long::LL &'
std::cout << NAMEOF_SHORT_TYPE(const Long::LL&) << std::endl; // 'LL'
std::cout << NAMEOF_SHORT_TYPE(const SomeClass<int>&) << std::endl; // 'SomeClass'
// Nameof variable type.
std::cout << nameof::nameof_type<decltype(structvar)>() << std::endl; // 'SomeStruct'
std::cout << NAMEOF_TYPE_EXPR(structvar) << std::endl; // 'SomeStruct'
std::cout << NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'SomeClass<int>'
std::cout << NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'const SomeClass<int> &&'
std::cout << NAMEOF_SHORT_TYPE_EXPR(std::declval<const SomeClass<int>>()) << std::endl; // 'SomeClass'
#if defined(NAMEOF_MEMBER_SUPPORTED)
// Nameof member
std::cout << nameof::nameof_member<&SomeStruct::somefield>() << std::endl; // somefield
std::cout << nameof::nameof_member<&SomeStruct::SomeMethod1>() << std::endl; // SomeMethod1
std::cout << NAMEOF_MEMBER(&Long::LL::field) << std::endl; // field
constexpr auto member_ptr = &SomeStruct::somefield;
std::cout << NAMEOF_MEMBER(member_ptr) << std::endl; // somefield
#endif
// Nameof macro.
std::cout << NAMEOF(__LINE__) << std::endl; // '__LINE__'
@ -161,6 +184,13 @@ int main() {
std::cout << NAMEOF_RAW(structvar.somefield) << std::endl; // 'structvar.somefield'
std::cout << NAMEOF_RAW(&SomeStruct::SomeMethod1) << std::endl; // '&SomeStruct::SomeMethod1'
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED)
// Nameof type using RTTI.
Base* ptr = new Derived();
std::cout << NAMEOF_TYPE_RTTI(ptr) << std::endl; // 'Base *'
std::cout << NAMEOF_TYPE_RTTI(*ptr) << std::endl; // 'Derived'
#endif
// Some more complex example.
std::cout << SomeMethod4<int>(structvar) << std::endl; // 'SomeMethod4<int, SomeStruct>(SomeStruct value)'

View file

@ -0,0 +1,93 @@
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2020 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <iostream>
#include <nameof.hpp>
enum class Color { RED = -10, BLUE = 0, GREEN = 10 };
enum class Numbers { One, Two, Three };
#if defined(NAMEOF_ENUM_SUPPORTED)
// Сustom definitions of names for enum.
// Specialization of `enum_name` must be injected in `namespace nameof::customize`.
template <>
constexpr std::string_view nameof::customize::enum_name<Color>(Color value) noexcept {
switch (value) {
case Color::RED:
return "the red color";
case Color::BLUE:
return "The BLUE";
case Color::GREEN:
return {}; // Empty string for default value.
}
return {}; // Empty string for unknown value.
}
// Сustom definitions of names for enum.
// Specialization of `enum_name` must be injected in `namespace nameof::customize`.
template <>
constexpr std::string_view nameof::customize::enum_name<Numbers>(Numbers value) noexcept {
switch (value) {
case Numbers::One:
return "the one";
default:
return {}; // Empty string for default or unknown value.
}
}
#endif
// Сustom definitions of names for type.
// Specialization of `type_name` must be injected in `namespace nameof::customize`.
template <>
constexpr std::string_view nameof::customize::type_name<Color>() noexcept {
return "The Color";
}
class a1_test {};
class a2_test {};
// Сustom definitions of names for type.
// Specialization of `type_name` must be injected in `namespace nameof::customize`.
template <>
constexpr std::string_view nameof::customize::type_name<a1_test>() noexcept {
return "Animal";
}
int main() {
#if defined(NAMEOF_ENUM_SUPPORTED)
std::cout << nameof::nameof_enum(Color::RED) << std::endl; // 'the red color'
std::cout << nameof::nameof_enum(Color::BLUE) << std::endl; // 'The BLUE'
std::cout << nameof::nameof_enum(Color::GREEN) << std::endl; // 'GREEN'
std::cout << nameof::nameof_enum(Numbers::One) << std::endl; // 'the one'
std::cout << nameof::nameof_enum(Numbers::Two) << std::endl; // 'Two'
std::cout << nameof::nameof_enum(Numbers::Three) << std::endl; // 'Three'
#endif
std::cout << nameof::nameof_type<Color>() << std::endl; // 'The Color'
std::cout << nameof::nameof_type<Numbers>() << std::endl; // 'Numbers'
std::cout << nameof::nameof_type<a1_test>() << std::endl; // 'Animal'
std::cout << nameof::nameof_type<a2_test>() << std::endl; // 'a2_test'
return 0;
}

View file

@ -0,0 +1,11 @@
import nameof;
#include <nameof_macro.hpp>
struct Test {};
auto main() -> int {
auto _ = nameof::nameof_type<Test>();
{
auto _ = NAMEOF_TYPE(Test);
}
}

File diff suppressed because it is too large Load diff

149
include/nameof_macro.hpp Normal file
View file

@ -0,0 +1,149 @@
#ifndef NEARGYE_NAMEOF_MACRO_HPP
#define NEARGYE_NAMEOF_MACRO_HPP
// Checks nameof_type compiler compatibility.
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 || defined(_MSC_VER) && _MSC_VER >= 1910
#undef NAMEOF_TYPE_SUPPORTED
#define NAMEOF_TYPE_SUPPORTED 1
#endif
// Checks nameof_type_rtti compiler compatibility.
#if defined(__clang__)
#if __has_feature(cxx_rtti)
#undef NAMEOF_TYPE_RTTI_SUPPORTED
#define NAMEOF_TYPE_RTTI_SUPPORTED 1
#endif
#elif defined(__GNUC__)
#if defined(__GXX_RTTI)
#undef NAMEOF_TYPE_RTTI_SUPPORTED
#define NAMEOF_TYPE_RTTI_SUPPORTED 1
#endif
#elif defined(_MSC_VER)
#if defined(_CPPRTTI)
#undef NAMEOF_TYPE_RTTI_SUPPORTED
#define NAMEOF_TYPE_RTTI_SUPPORTED 1
#endif
#endif
// Checks nameof_member compiler compatibility.
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 || \
defined(_MSC_VER) && defined(_MSVC_LANG) && _MSVC_LANG >= 202002L
#undef NAMEOF_MEMBER_SUPPORTED
#define NAMEOF_MEMBER_SUPPORTED 1
#endif
// Checks nameof_pointer compiler compatibility.
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 7 || \
defined(_MSC_VER) && defined(_MSVC_LANG) && _MSVC_LANG >= 202002L
#undef NAMEOF_POINTER_SUPPORTED
#define NAMEOF_POINTER_SUPPORTED 1
#endif
// Checks nameof_enum compiler compatibility.
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1910
#undef NAMEOF_ENUM_SUPPORTED
#define NAMEOF_ENUM_SUPPORTED 1
#endif
// Checks nameof_enum compiler aliases compatibility.
#if defined(__clang__) && __clang_major__ >= 5 || defined(__GNUC__) && __GNUC__ >= 9 || defined(_MSC_VER) && _MSC_VER >= 1920
#undef NAMEOF_ENUM_SUPPORTED_ALIASES
#define NAMEOF_ENUM_SUPPORTED_ALIASES 1
#endif
// Enum value must be greater or equals than NAMEOF_ENUM_RANGE_MIN. By default NAMEOF_ENUM_RANGE_MIN = -128.
// If need another min range for all enum types by default, redefine the macro NAMEOF_ENUM_RANGE_MIN.
#if !defined(NAMEOF_ENUM_RANGE_MIN)
#define NAMEOF_ENUM_RANGE_MIN -128
#endif
// Enum value must be less or equals than NAMEOF_ENUM_RANGE_MAX. By default NAMEOF_ENUM_RANGE_MAX = 128.
// If need another max range for all enum types by default, redefine the macro NAMEOF_ENUM_RANGE_MAX.
#if !defined(NAMEOF_ENUM_RANGE_MAX)
#define NAMEOF_ENUM_RANGE_MAX 128
#endif
#define NAMEOF_VERSION_MAJOR 0
#define NAMEOF_VERSION_MINOR 10
#define NAMEOF_VERSION_PATCH 4
// Obtains name of variable, function, macro.
#define NAMEOF(...) \
[]() constexpr noexcept { \
::std::void_t<decltype(__VA_ARGS__)>(); \
constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__); \
static_assert(!_name.empty(), "Expression does not have a name."); \
constexpr auto _size = _name.size(); \
constexpr auto _nameof = ::nameof::cstring<_size>{_name}; \
return _nameof; \
}()
// Obtains full name of variable, function, macro.
#define NAMEOF_FULL(...) \
[]() constexpr noexcept { \
::std::void_t<decltype(__VA_ARGS__)>(); \
constexpr auto _name = ::nameof::detail::pretty_name(#__VA_ARGS__, false); \
static_assert(!_name.empty(), "Expression does not have a name."); \
constexpr auto _size = _name.size(); \
constexpr auto _nameof_full = ::nameof::cstring<_size>{_name}; \
return _nameof_full; \
}()
// Obtains raw name of variable, function, macro.
#define NAMEOF_RAW(...) \
[]() constexpr noexcept { \
::std::void_t<decltype(__VA_ARGS__)>(); \
constexpr auto _name = ::nameof::string_view{#__VA_ARGS__}; \
static_assert(!_name.empty(), "Expression does not have a name."); \
constexpr auto _size = _name.size(); \
constexpr auto _nameof_raw = ::nameof::cstring<_size>{_name}; \
return _nameof_raw; \
}()
// Obtains name of enum variable.
#define NAMEOF_ENUM(...) ::nameof::nameof_enum<::std::decay_t<decltype(__VA_ARGS__)>>(__VA_ARGS__)
// Obtains name of enum variable or default value if enum variable out of range.
#define NAMEOF_ENUM_OR(...) ::nameof::nameof_enum_or(__VA_ARGS__)
// Obtains name of static storage enum variable.
// This version is much lighter on the compile times and is not restricted to the enum_range limitation.
#define NAMEOF_ENUM_CONST(...) ::nameof::nameof_enum<__VA_ARGS__>()
// Obtains name of enum-flags variable.
#define NAMEOF_ENUM_FLAG(...) ::nameof::nameof_enum_flag<::std::decay_t<decltype(__VA_ARGS__)>>(__VA_ARGS__)
// Obtains type name, reference and cv-qualifiers are ignored.
#define NAMEOF_TYPE(...) ::nameof::nameof_type<__VA_ARGS__>()
// Obtains full type name, with reference and cv-qualifiers.
#define NAMEOF_FULL_TYPE(...) ::nameof::nameof_full_type<__VA_ARGS__>()
// Obtains short type name.
#define NAMEOF_SHORT_TYPE(...) ::nameof::nameof_short_type<__VA_ARGS__>()
// Obtains type name of expression, reference and cv-qualifiers are ignored.
#define NAMEOF_TYPE_EXPR(...) ::nameof::nameof_type<decltype(__VA_ARGS__)>()
// Obtains full type name of expression, with reference and cv-qualifiers.
#define NAMEOF_FULL_TYPE_EXPR(...) ::nameof::nameof_full_type<decltype(__VA_ARGS__)>()
// Obtains short type name of expression.
#define NAMEOF_SHORT_TYPE_EXPR(...) ::nameof::nameof_short_type<decltype(__VA_ARGS__)>()
// Obtains type name, with reference and cv-qualifiers, using RTTI.
#define NAMEOF_TYPE_RTTI(...) ::nameof::detail::nameof_type_rtti<::std::void_t<decltype(__VA_ARGS__)>>(typeid(__VA_ARGS__).name())
// Obtains full type name, using RTTI.
#define NAMEOF_FULL_TYPE_RTTI(...) ::nameof::detail::nameof_full_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name())
// Obtains short type name, using RTTI.
#define NAMEOF_SHORT_TYPE_RTTI(...) ::nameof::detail::nameof_short_type_rtti<decltype(__VA_ARGS__)>(typeid(__VA_ARGS__).name())
// Obtains name of member.
#define NAMEOF_MEMBER(...) ::nameof::nameof_member<__VA_ARGS__>()
// Obtains name of a function, a global or class static variable.
#define NAMEOF_POINTER(...) ::nameof::nameof_pointer<__VA_ARGS__>()
#endif

46
src/nameof.cpp Normal file
View file

@ -0,0 +1,46 @@
module;
#ifndef NAMEOF_IMPORT_STD
#include <array>
#include <cassert>
#include <cstddef>
#include <cstdint>
#include <iosfwd>
#include <iterator>
#include <limits>
#include <type_traits>
#include <utility>
#if !defined(NAMEOF_USING_ALIAS_STRING)
#include <string>
#endif
#if !defined(NAMEOF_USING_ALIAS_STRING_VIEW)
#include <string_view>
#endif
#if __has_include(<cxxabi.h>)
#include <cxxabi.h>
#include <cstdlib>
#endif
#endif
export module nameof;
#ifdef NAMEOF_IMPORT_STD
import std;
#endif
#ifdef NAMEOF_ATTACH_TO_GLOBAL_MODULE
extern "C++" {
#endif
#include <nameof.hpp>
#ifdef NAMEOF_ATTACH_TO_GLOBAL_MODULE
} // extern "C++"
#endif

File diff suppressed because it is too large Load diff

View file

@ -1,7 +1,5 @@
include(CheckCXXCompilerFlag)
set(SOURCES test.cpp)
if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
set(OPTIONS /W4 /WX)
check_cxx_compiler_flag(/permissive HAS_PERMISSIVE_FLAG)
@ -10,16 +8,18 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
endif()
check_cxx_compiler_flag(/std:c++20 HAS_CPP20_FLAG)
check_cxx_compiler_flag(/std:c++23 HAS_CPP23_FLAG)
check_cxx_compiler_flag(/std:c++latest HAS_CPPLATEST_FLAG)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
set(CMAKE_VERBOSE_MAKEFILE ON)
set(OPTIONS -Wall -Wextra -pedantic-errors -Werror)
check_cxx_compiler_flag(-std=c++20 HAS_CPP20_FLAG)
check_cxx_compiler_flag(-std=c++23 HAS_CPP23_FLAG)
endif()
function(make_test target std)
add_executable(${target} ${SOURCES})
function(make_test src target std)
add_executable(${target} ${src})
target_compile_options(${target} PRIVATE ${OPTIONS})
target_include_directories(${target} PRIVATE 3rdparty/Catch2)
target_link_libraries(${target} PRIVATE ${CMAKE_PROJECT_NAME})
@ -34,12 +34,20 @@ function(make_test target std)
add_test(NAME ${target} COMMAND ${target})
endfunction()
make_test(${CMAKE_PROJECT_NAME}-cpp17.t c++17)
make_test(test.cpp test-cpp17 c++17)
make_test(test_aliases.cpp test_aliases-cpp17 c++17)
if(HAS_CPP20_FLAG)
make_test(${CMAKE_PROJECT_NAME}-cpp20.t c++20)
make_test(test.cpp test-cpp20 c++20)
make_test(test_aliases.cpp test_aliases-cpp20 c++20)
endif()
if(HAS_CPP23_FLAG)
make_test(test.cpp test-cpp23 c++23)
make_test(test_aliases.cpp test_aliases-cpp23 c++23)
endif()
if(HAS_CPPLATEST_FLAG)
make_test(${CMAKE_PROJECT_NAME}-cpplatest.t c++latest)
make_test(test.cpp test-cpplatest c++latest)
make_test(test_aliases.cpp test_aliases-cpplatest c++latest)
endif()

View file

@ -1,6 +1,6 @@
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2018 - 2019 Daniil Goncharov <neargye@gmail.com>.
// Copyright (c) 2018 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
@ -30,6 +30,12 @@
#include <string>
#include <stdexcept>
#ifdef NDEBUG
# define NAMEOF_DEBUG_REQUIRE(...) REQUIRE(__VA_ARGS__)
#else
# define NAMEOF_DEBUG_REQUIRE(...)
#endif
struct SomeStruct {
int somefield = 0;
@ -40,8 +46,16 @@ struct SomeStruct {
int SomeMethod2() const {
throw std::runtime_error{"should not be called!"};
}
static int somestaticfield;
constexpr static int someotherstaticfield = 21;
};
int SomeStruct::somestaticfield;
int someglobalvariable = 0;
const int someglobalconstvariable = 42;
void SomeMethod3() {
throw std::runtime_error{"should not be called!"};
}
@ -79,20 +93,43 @@ enum Directions { Up = 85, Down = -42, Right = 120, Left = -120 };
enum number : unsigned long { one = 100, two = 200, three = 300, four = 400 };
namespace nameof {
enum AnimalFlags {
HasClaws = 1,
CanFly = 2,
EatsFish = 4,
Endangered = 8,
};
enum class BigFlags : std::uint64_t {
A = 1,
B = (static_cast<std::uint64_t>(0x1) << 20),
C = (static_cast<std::uint64_t>(0x1) << 40),
D = (static_cast<std::uint64_t>(0x1) << 63),
};
template <>
struct enum_range<number> {
struct nameof::customize::enum_range<number> {
static_assert(std::is_enum_v<number>, "nameof::enum_range<number> requires enum type.");
static constexpr int min = 100;
static constexpr int max = 300;
static_assert(max > min, "nameof::enum_range<number> requires max > min.");
};
}
enum class OutOfRange {
too_low = NAMEOF_ENUM_RANGE_MIN - 1,
required_to_work = 0,
too_high = NAMEOF_ENUM_RANGE_MAX + 1
};
struct TestRtti {
struct Base { virtual ~Base() = default; };
struct Derived : Base {};
};
SomeStruct struct_var;
Long othervar;
SomeStruct * ptr_s = &struct_var;
SomeStruct & ref_s = struct_var;
SomeStruct* ptr_s = &struct_var;
SomeStruct& ref_s = struct_var;
SomeClass<int> class_var;
const SomeClass<int> volatile * ptr_c = nullptr;
@ -229,70 +266,6 @@ TEST_CASE("NAMEOF_RAW") {
static_assert(nameof::is_nameof_enum_supported, "nameof::nameof_enum: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
TEST_CASE("NAMEOF_ENUM") {
constexpr Color cr = Color::RED;
constexpr auto cr_name = NAMEOF_ENUM(cr);
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
REQUIRE(cr_name == "RED");
REQUIRE(NAMEOF_ENUM(Color::BLUE) == "BLUE");
REQUIRE(NAMEOF_ENUM(cm[1]) == "GREEN");
REQUIRE(NAMEOF_ENUM(static_cast<Color>(0)).empty());
constexpr Numbers no = Numbers::one;
constexpr auto no_name = NAMEOF_ENUM(no);
REQUIRE(no_name == "one");
REQUIRE(NAMEOF_ENUM(Numbers::two) == "two");
REQUIRE(NAMEOF_ENUM(Numbers::three) == "three");
REQUIRE(NAMEOF_ENUM(Numbers::many).empty());
REQUIRE(NAMEOF_ENUM(static_cast<Numbers>(0)).empty());
constexpr Directions dr = Directions::Right;
constexpr auto dr_name = NAMEOF_ENUM(dr);
REQUIRE(NAMEOF_ENUM(Directions::Up) == "Up");
REQUIRE(NAMEOF_ENUM(Directions::Down) == "Down");
REQUIRE(dr_name == "Right");
REQUIRE(NAMEOF_ENUM(Directions::Left) == "Left");
REQUIRE(NAMEOF_ENUM(static_cast<Directions>(0)).empty());
constexpr number nt = number::three;
constexpr auto nt_name = NAMEOF_ENUM(nt);
REQUIRE(NAMEOF_ENUM(number::one) == "one");
REQUIRE(NAMEOF_ENUM(number::two) == "two");
REQUIRE(nt_name == "three");
REQUIRE(NAMEOF_ENUM(number::four).empty());
REQUIRE(NAMEOF_ENUM(static_cast<number>(0)).empty());
}
TEST_CASE("NAMEOF_CONST_ENUM") {
constexpr Color cr = Color::RED;
constexpr auto cr_name = NAMEOF_CONST_ENUM(cr);
constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
REQUIRE(cr_name == "RED");
REQUIRE(NAMEOF_CONST_ENUM(Color::BLUE) == "BLUE");
REQUIRE(NAMEOF_CONST_ENUM(cm[1]) == "GREEN");
constexpr Numbers no = Numbers::one;
constexpr auto no_name = NAMEOF_CONST_ENUM(no);
REQUIRE(no_name == "one");
REQUIRE(NAMEOF_CONST_ENUM(Numbers::two) == "two");
REQUIRE(NAMEOF_CONST_ENUM(Numbers::three) == "three");
REQUIRE(NAMEOF_CONST_ENUM(Numbers::many) == "many");
constexpr Directions dr = Directions::Right;
constexpr auto dr_name = NAMEOF_CONST_ENUM(dr);
REQUIRE(NAMEOF_CONST_ENUM(Directions::Up) == "Up");
REQUIRE(NAMEOF_CONST_ENUM(Directions::Down) == "Down");
REQUIRE(dr_name == "Right");
REQUIRE(NAMEOF_CONST_ENUM(Directions::Left) == "Left");
constexpr number nt = number::three;
constexpr auto nt_name = NAMEOF_CONST_ENUM(nt);
REQUIRE(NAMEOF_CONST_ENUM(number::one) == "one");
REQUIRE(NAMEOF_CONST_ENUM(number::two) == "two");
REQUIRE(nt_name == "three");
REQUIRE(NAMEOF_CONST_ENUM(number::four) == "four");
}
TEST_CASE("nameof_enum") {
SECTION("automatic storage") {
constexpr Color cr = Color::RED;
@ -301,15 +274,15 @@ TEST_CASE("nameof_enum") {
REQUIRE(cr_name == "RED");
REQUIRE(nameof::nameof_enum(Color::BLUE) == "BLUE");
REQUIRE(nameof::nameof_enum(cm[1]) == "GREEN");
REQUIRE(nameof::nameof_enum(static_cast<Color>(0)).empty());
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Color>(0)).empty());
constexpr Numbers no = Numbers::one;
constexpr auto no_name = nameof::nameof_enum(no);
REQUIRE(no_name == "one");
REQUIRE(nameof::nameof_enum(Numbers::two) == "two");
REQUIRE(nameof::nameof_enum(Numbers::three) == "three");
REQUIRE(nameof::nameof_enum(Numbers::many).empty());
REQUIRE(nameof::nameof_enum(static_cast<Numbers>(0)).empty());
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(Numbers::many).empty());
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Numbers>(0)).empty());
constexpr Directions dr = Directions::Right;
constexpr auto dr_name = nameof::nameof_enum(dr);
@ -317,15 +290,15 @@ TEST_CASE("nameof_enum") {
REQUIRE(nameof::nameof_enum(Directions::Down) == "Down");
REQUIRE(dr_name == "Right");
REQUIRE(nameof::nameof_enum(Directions::Left) == "Left");
REQUIRE(nameof::nameof_enum(static_cast<Directions>(0)).empty());
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<Directions>(0)).empty());
constexpr number nt = number::three;
constexpr auto nt_name = nameof::nameof_enum(nt);
REQUIRE(nameof::nameof_enum(number::one) == "one");
REQUIRE(nameof::nameof_enum(number::two) == "two");
REQUIRE(nt_name == "three");
REQUIRE(nameof::nameof_enum(number::four).empty());
REQUIRE(nameof::nameof_enum(static_cast<number>(0)).empty());
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(number::four).empty());
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum(static_cast<number>(0)).empty());
}
SECTION("static storage") {
@ -359,112 +332,211 @@ TEST_CASE("nameof_enum") {
}
}
TEST_CASE("nameof_enum_flag") {
constexpr AnimalFlags af = AnimalFlags::HasClaws;
auto af_name = nameof::nameof_enum_flag(af);
AnimalFlags afm[3] = {AnimalFlags::HasClaws, AnimalFlags::CanFly, AnimalFlags::EatsFish};
REQUIRE(af_name == "HasClaws");
REQUIRE(nameof::nameof_enum_flag(AnimalFlags::EatsFish) == "EatsFish");
REQUIRE(nameof::nameof_enum_flag(afm[1]) == "CanFly");
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(0)).empty());
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 2)) == "HasClaws|CanFly");
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 2 | 4)) == "HasClaws|CanFly|EatsFish");
REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(1 | 0 | 8)) == "HasClaws|Endangered");
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<AnimalFlags>(0)).empty());
constexpr BigFlags bf = BigFlags::A;
auto bf_name = nameof::nameof_enum_flag(bf);
BigFlags bfm[3] = {BigFlags::A, BigFlags::B, BigFlags::C};
REQUIRE(bf_name == "A");
REQUIRE(nameof::nameof_enum_flag(BigFlags::C) == "C");
REQUIRE(nameof::nameof_enum_flag(bfm[1]) == "B");
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(0)).empty());
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 2)).empty());
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20))) == "A|B");
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20) | (static_cast<std::uint64_t>(0x1) << 63))) == "A|B|D");
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 0 | (static_cast<std::uint64_t>(0x1) << 40))) == "A|C");
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(1 | 0 | (static_cast<std::uint64_t>(0x1) << 40))) == "A|C");
REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 1)) == "A|D");
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>(2)).empty());
NAMEOF_DEBUG_REQUIRE(nameof::nameof_enum_flag(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
}
TEST_CASE("NAMEOF_ENUM") {
constexpr Color cr = Color::RED;
constexpr auto cr_name = NAMEOF_ENUM(cr);
Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
REQUIRE(cr_name == "RED");
REQUIRE(NAMEOF_ENUM(Color::BLUE) == "BLUE");
REQUIRE(NAMEOF_ENUM(cm[1]) == "GREEN");
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Color>(0)).empty());
constexpr Numbers no = Numbers::one;
constexpr auto no_name = NAMEOF_ENUM(no);
REQUIRE(no_name == "one");
REQUIRE(NAMEOF_ENUM(Numbers::two) == "two");
REQUIRE(NAMEOF_ENUM(Numbers::three) == "three");
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(Numbers::many).empty());
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Numbers>(0)).empty());
constexpr Directions dr = Directions::Right;
constexpr auto dr_name = NAMEOF_ENUM(dr);
REQUIRE(NAMEOF_ENUM(Directions::Up) == "Up");
REQUIRE(NAMEOF_ENUM(Directions::Down) == "Down");
REQUIRE(dr_name == "Right");
REQUIRE(NAMEOF_ENUM(Directions::Left) == "Left");
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<Directions>(0)).empty());
constexpr number nt = number::three;
constexpr auto nt_name = NAMEOF_ENUM(nt);
REQUIRE(NAMEOF_ENUM(number::one) == "one");
REQUIRE(NAMEOF_ENUM(number::two) == "two");
REQUIRE(nt_name == "three");
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(number::four).empty());
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM(static_cast<number>(0)).empty());
}
TEST_CASE("NAMEOF_ENUM_CONST") {
constexpr Color cr = Color::RED;
constexpr auto cr_name = NAMEOF_ENUM_CONST(cr);
constexpr Color cm[3] = {Color::RED, Color::GREEN, Color::BLUE};
REQUIRE(cr_name == "RED");
REQUIRE(NAMEOF_ENUM_CONST(Color::BLUE) == "BLUE");
REQUIRE(NAMEOF_ENUM_CONST(cm[1]) == "GREEN");
constexpr Numbers no = Numbers::one;
constexpr auto no_name = NAMEOF_ENUM_CONST(no);
REQUIRE(no_name == "one");
REQUIRE(NAMEOF_ENUM_CONST(Numbers::two) == "two");
REQUIRE(NAMEOF_ENUM_CONST(Numbers::three) == "three");
REQUIRE(NAMEOF_ENUM_CONST(Numbers::many) == "many");
constexpr Directions dr = Directions::Right;
constexpr auto dr_name = NAMEOF_ENUM_CONST(dr);
REQUIRE(NAMEOF_ENUM_CONST(Directions::Up) == "Up");
REQUIRE(NAMEOF_ENUM_CONST(Directions::Down) == "Down");
REQUIRE(dr_name == "Right");
REQUIRE(NAMEOF_ENUM_CONST(Directions::Left) == "Left");
constexpr number nt = number::three;
constexpr auto nt_name = NAMEOF_ENUM_CONST(nt);
REQUIRE(NAMEOF_ENUM_CONST(number::one) == "one");
REQUIRE(NAMEOF_ENUM_CONST(number::two) == "two");
REQUIRE(nt_name == "three");
REQUIRE(NAMEOF_ENUM_CONST(number::four) == "four");
}
TEST_CASE("NAMEOF_ENUM_FLAG") {
constexpr AnimalFlags af = AnimalFlags::HasClaws;
auto af_name = NAMEOF_ENUM_FLAG(af);
AnimalFlags afm[3] = {AnimalFlags::HasClaws, AnimalFlags::CanFly, AnimalFlags::EatsFish};
REQUIRE(af_name == "HasClaws");
REQUIRE(NAMEOF_ENUM_FLAG(afm[1]) == "CanFly");
REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::EatsFish) == "EatsFish");
REQUIRE(NAMEOF_ENUM_FLAG(AnimalFlags::Endangered) == "Endangered");
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(0)).empty());
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 2)) == "HasClaws|CanFly");
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 2 | 4)) == "HasClaws|CanFly|EatsFish");
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(1 | 0 | 8)) == "HasClaws|Endangered");
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<AnimalFlags>(0)).empty());
constexpr BigFlags bf = BigFlags::A;
auto bf_name = NAMEOF_ENUM_FLAG(bf);
BigFlags bfm[3] = {BigFlags::A, BigFlags::B, BigFlags::C};
REQUIRE(bf_name == "A");
REQUIRE(NAMEOF_ENUM_FLAG(bfm[1]) == "B");
REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::C) == "C");
REQUIRE(NAMEOF_ENUM_FLAG(BigFlags::D) == "D");
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(0)).empty());
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | 2)).empty());
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20))) == "A|B");
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(1 | (static_cast<std::uint64_t>(0x1) << 20) | (static_cast<std::uint64_t>(0x1) << 63))) == "A|B|D");
REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 1)) == "A|D");
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>(2)).empty());
NAMEOF_DEBUG_REQUIRE(NAMEOF_ENUM_FLAG(static_cast<BigFlags>((static_cast<std::uint64_t>(0x1) << 63) | 2)).empty());
}
TEST_CASE("nameof_enum_or") {
OutOfRange low = OutOfRange::too_low;
OutOfRange high = OutOfRange::too_high;
auto low_name = nameof::nameof_enum_or(low, "-121");
auto high_name = nameof::nameof_enum_or(high, "121");
constexpr OutOfRange oor[] = {OutOfRange::too_high, OutOfRange::too_low};
REQUIRE(low_name == "-121");
REQUIRE(high_name == "121");
REQUIRE(nameof::nameof_enum_or(oor[0], "121") == "121");
}
TEST_CASE("NAMEOF_ENUM_OR") {
OutOfRange low = OutOfRange::too_low;
OutOfRange high = OutOfRange::too_high;
auto low_name = NAMEOF_ENUM_OR(low, "-121");
auto high_name = NAMEOF_ENUM_OR(high, "121");
constexpr OutOfRange oor[] = {OutOfRange::too_high, OutOfRange::too_low};
REQUIRE(low_name == "-121");
REQUIRE(high_name == "121");
REQUIRE(NAMEOF_ENUM_OR(oor[0], "121") == "121");
}
#endif
#if defined(NAMEOF_TYPE_SUPPORTED)
static_assert(nameof::is_nameof_type_supported, "nameof::nameof_type: Unsupported compiler (https://github.com/Neargye/nameof#compiler-compatibility).");
TEST_CASE("NAMEOF_FULL_TYPE_EXPR") {
constexpr auto type_name = NAMEOF_FULL_TYPE_EXPR(struct_var);
TEST_CASE("nameof::nameof_type") {
constexpr auto type_name = nameof::nameof_type<decltype(struct_var)>();
#if defined(__clang__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct &");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct *");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct *");
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int> *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
REQUIRE(nameof::nameof_type<Long>() == "Long");
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int> &&");
REQUIRE(nameof::nameof_type<Color>() == "Color");
#elif defined(_MSC_VER)
REQUIRE(type_name == "struct SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "struct SomeStruct &");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "struct SomeStruct *");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "struct SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct>() == "struct SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct *>() == "struct SomeStruct *");
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "struct SomeStruct");
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "struct SomeStruct const volatile *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "class SomeClass<int>");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "class SomeClass<int> const volatile *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "struct Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "struct Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "struct Long");
REQUIRE(nameof::nameof_type<Long>() == "struct Long");
REQUIRE(nameof::nameof_type<Long::LL>() == "struct Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "enum Color");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int> const &&");
REQUIRE(nameof::nameof_type<Color>() == "enum Color");
#elif defined(__GNUC__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct&");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct*");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct*");
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int>*");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
REQUIRE(nameof::nameof_type<Long>() == "Long");
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int>&&");
#endif
}
TEST_CASE("NAMEOF_FULL_TYPE") {
constexpr auto type_name = NAMEOF_FULL_TYPE(decltype(struct_var));
#if defined(__clang__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int> *");
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
#elif defined(_MSC_VER)
REQUIRE(type_name == "struct SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "struct SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "struct SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "struct SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "struct SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "struct SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "struct SomeStruct const volatile *");
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "class SomeClass<int>");
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "class SomeClass<int> const volatile *");
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "struct Long");
REQUIRE(NAMEOF_FULL_TYPE(Long) == "struct Long");
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "struct Long::LL");
REQUIRE(NAMEOF_FULL_TYPE(Color) == "enum Color");
#elif defined(__GNUC__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct&");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct&");
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int>*");
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
REQUIRE(nameof::nameof_type<Color>() == "Color");
#endif
}
@ -524,51 +596,22 @@ TEST_CASE("nameof::nameof_full_type") {
#endif
}
TEST_CASE("NAMEOF_TYPE_EXPR") {
constexpr auto type_name = NAMEOF_TYPE_EXPR(struct_var);
#if defined(__clang__)
TEST_CASE("nameof::nameof_short_type") {
constexpr auto type_name = nameof::nameof_short_type<decltype(struct_var)>();
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct *");
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
REQUIRE(nameof::nameof_short_type<decltype(ref_s)>() == "SomeStruct");
REQUIRE(nameof::nameof_short_type<SomeStruct>() == "SomeStruct");
REQUIRE(nameof::nameof_short_type<SomeStruct &>() == "SomeStruct");
REQUIRE(nameof::nameof_short_type<const SomeStruct volatile>() == "SomeStruct");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
REQUIRE(nameof::nameof_short_type<SomeClass<int>>() == "SomeClass");
REQUIRE(nameof::nameof_short_type<const SomeClass<int> volatile>() == "SomeClass");
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(nameof::nameof_short_type<decltype(othervar)>() == "Long");
REQUIRE(nameof::nameof_short_type<Long>() == "Long");
REQUIRE(nameof::nameof_short_type<Long::LL>() == "LL");
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
#elif defined(_MSC_VER)
REQUIRE(type_name == "struct SomeStruct");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "struct SomeStruct");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "struct Long");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "struct Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "enum Color");
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int>");
#elif defined(__GNUC__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct*");
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
#endif
REQUIRE(nameof::nameof_short_type<Color>() == "Color");
}
TEST_CASE("NAMEOF_TYPE") {
@ -627,60 +670,309 @@ TEST_CASE("NAMEOF_TYPE") {
#endif
}
TEST_CASE("nameof::nameof_type") {
constexpr auto type_name = nameof::nameof_type<decltype(struct_var)>();
TEST_CASE("NAMEOF_TYPE_EXPR") {
constexpr auto type_name = NAMEOF_TYPE_EXPR(struct_var);
#if defined(__clang__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct *");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct *");
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct *");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct *");
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int> *");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
REQUIRE(nameof::nameof_type<Long>() == "Long");
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(nameof::nameof_type<Color>() == "Color");
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
#elif defined(_MSC_VER)
REQUIRE(type_name == "struct SomeStruct");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "struct SomeStruct *");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "struct SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct>() == "struct SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct *>() == "struct SomeStruct *");
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "struct SomeStruct");
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "struct SomeStruct const volatile *");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "struct SomeStruct");
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "class SomeClass<int>");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "class SomeClass<int> const volatile *");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "struct Long");
REQUIRE(nameof::nameof_type<Long>() == "struct Long");
REQUIRE(nameof::nameof_type<Long::LL>() == "struct Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "struct Long");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "struct Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(nameof::nameof_type<Color>() == "enum Color");
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "enum Color");
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int>");
#elif defined(__GNUC__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(nameof::nameof_type<decltype(ptr_s)>() == "SomeStruct*");
REQUIRE(nameof::nameof_type<decltype(ref_s)>() == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct>() == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeStruct *>() == "SomeStruct*");
REQUIRE(nameof::nameof_type<const SomeStruct &>() == "SomeStruct");
REQUIRE(nameof::nameof_type<const SomeStruct volatile *>() == "const volatile SomeStruct*");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_s) == "SomeStruct*");
REQUIRE(NAMEOF_TYPE_EXPR(ref_s) == "SomeStruct");
REQUIRE(nameof::nameof_type<SomeClass<int>>() == "SomeClass<int>");
REQUIRE(nameof::nameof_type<const SomeClass<int> volatile *>() == "const volatile SomeClass<int>*");
REQUIRE(NAMEOF_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
REQUIRE(nameof::nameof_type<decltype(othervar)>() == "Long");
REQUIRE(nameof::nameof_type<Long>() == "Long");
REQUIRE(nameof::nameof_type<Long::LL>() == "Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(NAMEOF_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(nameof::nameof_type<Color>() == "Color");
REQUIRE(NAMEOF_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass<int>");
#endif
}
TEST_CASE("NAMEOF_FULL_TYPE") {
constexpr auto type_name = NAMEOF_FULL_TYPE(decltype(struct_var));
#if defined(__clang__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int> *");
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
#elif defined(_MSC_VER)
REQUIRE(type_name == "struct SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "struct SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "struct SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "struct SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "struct SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "struct SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "struct SomeStruct const volatile *");
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "class SomeClass<int>");
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "class SomeClass<int> const volatile *");
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "struct Long");
REQUIRE(NAMEOF_FULL_TYPE(Long) == "struct Long");
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "struct Long::LL");
REQUIRE(NAMEOF_FULL_TYPE(Color) == "enum Color");
#elif defined(__GNUC__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ptr_s)) == "SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE(decltype(ref_s)) == "SomeStruct&");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct) == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct *) == "SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE(SomeStruct &) == "SomeStruct&");
REQUIRE(NAMEOF_FULL_TYPE(const SomeStruct volatile *) == "const volatile SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE(SomeClass<int>) == "SomeClass<int>");
REQUIRE(NAMEOF_FULL_TYPE(const SomeClass<int> volatile *) == "const volatile SomeClass<int>*");
REQUIRE(NAMEOF_FULL_TYPE(decltype(othervar)) == "Long");
REQUIRE(NAMEOF_FULL_TYPE(Long) == "Long");
REQUIRE(NAMEOF_FULL_TYPE(Long::LL) == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE(Color) == "Color");
#endif
}
TEST_CASE("NAMEOF_FULL_TYPE_EXPR") {
constexpr auto type_name = NAMEOF_FULL_TYPE_EXPR(struct_var);
#if defined(__clang__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int> *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int> &&");
#elif defined(_MSC_VER)
REQUIRE(type_name == "struct SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "struct SomeStruct *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "struct SomeStruct &");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "class SomeClass<int> const volatile *");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "struct Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "struct Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "enum Color");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "class SomeClass<int> const &&");
#elif defined(__GNUC__)
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_s) == "SomeStruct*");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ref_s) == "SomeStruct&");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(ptr_c) == "const volatile SomeClass<int>*");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll) == "Long::LL");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_FULL_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "const SomeClass<int>&&");
#endif
}
TEST_CASE("NAMEOF_SHORT_TYPE") {
constexpr auto type_name = NAMEOF_SHORT_TYPE(decltype(struct_var));
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_SHORT_TYPE(decltype(ref_s)) == "SomeStruct");
REQUIRE(NAMEOF_SHORT_TYPE(SomeStruct) == "SomeStruct");
REQUIRE(NAMEOF_SHORT_TYPE(SomeStruct &) == "SomeStruct");
REQUIRE(NAMEOF_SHORT_TYPE(const SomeStruct volatile) == "SomeStruct");
REQUIRE(NAMEOF_SHORT_TYPE(SomeClass<int>) == "SomeClass");
REQUIRE(NAMEOF_SHORT_TYPE(const SomeClass<int> volatile) == "SomeClass");
REQUIRE(NAMEOF_SHORT_TYPE(decltype(othervar)) == "Long");
REQUIRE(NAMEOF_SHORT_TYPE(Long) == "Long");
REQUIRE(NAMEOF_SHORT_TYPE(Long::LL) == "LL");
REQUIRE(NAMEOF_SHORT_TYPE(Color) == "Color");
}
TEST_CASE("NAMEOF_SHORT_TYPE_EXPR") {
constexpr auto type_name = NAMEOF_SHORT_TYPE_EXPR(struct_var);
REQUIRE(type_name == "SomeStruct");
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(ref_s) == "SomeStruct");
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar) == "Long");
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar.ll) == "LL");
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(othervar.ll.field) == "int");
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(Color::RED) == "Color");
REQUIRE(NAMEOF_SHORT_TYPE_EXPR(std::declval<const SomeClass<int>>()) == "SomeClass");
}
#endif
#if defined(NAMEOF_TYPE_RTTI_SUPPORTED) && NAMEOF_TYPE_RTTI_SUPPORTED
TEST_CASE("NAMEOF_TYPE_RTTI") {
TestRtti::Base* ptr = new TestRtti::Derived();
const TestRtti::Base& const_ref = *ptr;
volatile TestRtti::Base& volatile_ref = *ptr;
volatile const TestRtti::Base& cv_ref = *ptr;
#if defined(__clang__) && !defined(_MSC_VER)
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "TestRtti::Derived");
#elif defined(_MSC_VER)
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "struct TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "struct TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "struct TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "struct TestRtti::Derived");
#elif defined(__GNUC__)
REQUIRE(NAMEOF_TYPE_RTTI(*ptr) == "TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(const_ref) == "TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(volatile_ref) == "TestRtti::Derived");
REQUIRE(NAMEOF_TYPE_RTTI(cv_ref) == "TestRtti::Derived");
#endif
}
TEST_CASE("NAMEOF_FULL_TYPE_RTTI") {
TestRtti::Base* ptr = new TestRtti::Derived();
const TestRtti::Base& const_ref = *ptr;
volatile TestRtti::Base& volatile_ref = *ptr;
volatile const TestRtti::Base& cv_ref = *ptr;
#if defined(__clang__) && !defined(_MSC_VER)
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const TestRtti::Derived&");
#elif defined(_MSC_VER)
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "struct TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const struct TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile struct TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const struct TestRtti::Derived&");
#elif defined(__GNUC__)
REQUIRE(NAMEOF_FULL_TYPE_RTTI(*ptr) == "TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(const_ref) == "const TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(volatile_ref) == "volatile TestRtti::Derived&");
REQUIRE(NAMEOF_FULL_TYPE_RTTI(cv_ref) == "volatile const TestRtti::Derived&");
#endif
}
TEST_CASE("NAMEOF_SHORT_TYPE_RTTI") {
TestRtti::Base* ptr = new TestRtti::Derived();
const TestRtti::Base& const_ref = *ptr;
volatile TestRtti::Base& volatile_ref = *ptr;
volatile const TestRtti::Base& cv_ref = *ptr;
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(*ptr) == "Derived");
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(const_ref) == "Derived");
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(volatile_ref) == "Derived");
REQUIRE(NAMEOF_SHORT_TYPE_RTTI(cv_ref) == "Derived");
}
#endif
#if defined(NAMEOF_MEMBER_SUPPORTED) && NAMEOF_MEMBER_SUPPORTED
struct StructMemberInitializationUsingNameof {
std::string teststringfield = std::string{nameof::nameof_member<&StructMemberInitializationUsingNameof::teststringfield>()};
};
struct StructWithNonConstexprDestructor {
~StructWithNonConstexprDestructor() {}
int somefield;
};
TEST_CASE("NAMEOF_MEMBER") {
REQUIRE(NAMEOF_MEMBER(&SomeStruct::somefield) == "somefield");
REQUIRE(NAMEOF_MEMBER(&SomeStruct::SomeMethod1) == "SomeMethod1");
REQUIRE(NAMEOF_MEMBER(&Long::LL::field) == "field");
constexpr auto member_ptr = &SomeStruct::somefield;
REQUIRE(NAMEOF_MEMBER(member_ptr) == "somefield");
REQUIRE(NAMEOF_MEMBER(&StructMemberInitializationUsingNameof::teststringfield) == "teststringfield");
REQUIRE(NAMEOF_MEMBER(&StructWithNonConstexprDestructor::somefield) == "somefield");
}
TEST_CASE("nameof_member") {
REQUIRE(nameof::nameof_member<&SomeStruct::somefield>() == "somefield");
REQUIRE(nameof::nameof_member<&SomeStruct::SomeMethod1>() == "SomeMethod1");
REQUIRE(nameof::nameof_member<&Long::LL::field>() == "field");
constexpr auto member_ptr = &SomeStruct::somefield;
REQUIRE(nameof::nameof_member<member_ptr>() == "somefield");
REQUIRE(nameof::nameof_member<&StructMemberInitializationUsingNameof::teststringfield>() == "teststringfield");
REQUIRE(nameof::nameof_member<&StructWithNonConstexprDestructor::somefield>() == "somefield");
}
#endif
#if defined(NAMEOF_POINTER_SUPPORTED) && NAMEOF_POINTER_SUPPORTED
void somefunction() {}
TEST_CASE("NAMEOF_POINTER") {
REQUIRE(NAMEOF_POINTER(&SomeStruct::somestaticfield) == "somestaticfield");
REQUIRE(NAMEOF_POINTER(&SomeStruct::someotherstaticfield) == "someotherstaticfield");
REQUIRE(NAMEOF_POINTER(static_cast<const char*>(nullptr)) == "nullptr");
REQUIRE(NAMEOF_POINTER(static_cast<int***>(nullptr)) == "nullptr");
constexpr auto global_ptr = &someglobalvariable;
REQUIRE(NAMEOF_POINTER(global_ptr) == "someglobalvariable");
REQUIRE(NAMEOF_POINTER(&someglobalconstvariable) == "someglobalconstvariable");
REQUIRE(NAMEOF_POINTER(&somefunction) == "somefunction");
}
TEST_CASE("nameof_pointer") {
REQUIRE(nameof::nameof_pointer<&SomeStruct::somestaticfield>() == "somestaticfield");
REQUIRE(nameof::nameof_pointer<&SomeStruct::someotherstaticfield>() == "someotherstaticfield");
REQUIRE(nameof::nameof_pointer<static_cast<const char*>(nullptr)>() == "nullptr");
REQUIRE(nameof::nameof_pointer<static_cast<int***>(nullptr)>() == "nullptr");
constexpr auto global_ptr = &someglobalvariable;
REQUIRE(nameof::nameof_pointer<global_ptr>() == "someglobalvariable");
REQUIRE(nameof::nameof_pointer<&someglobalconstvariable>() == "someglobalconstvariable");
REQUIRE(nameof::nameof_pointer<&somefunction>() == "somefunction");
}
#endif

97
test/test_aliases.cpp Normal file
View file

@ -0,0 +1,97 @@
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// SPDX-License-Identifier: MIT
// Copyright (c) 2019 - 2024 Daniil Goncharov <neargye@gmail.com>.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
#include <string>
#include <string_view>
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
struct MyString {
MyString() : str{} {} // required
MyString(const char* s) : str{s} {} // required
MyString(const char* s, std::size_t l) : str{s, l} {} // required
bool empty() const { return str.empty(); } // required
MyString& append(std::size_t count, char c) { str.append(count, c); return *this; } // required
MyString& append(const char* s, std::size_t count) { str.append(s, count); return *this; } // required
MyString& append(const MyString& s) { str.append(s.str); return *this; } // required
std::size_t size() const { return str.size(); }
int compare(const char* s) const { return str.compare(s); }
private:
std::string str;
};
struct MyStringView {
using value_type = char; // required
static constexpr auto npos = std::string_view::npos; // required
constexpr MyStringView() : str{} {} // required
constexpr MyStringView(const char* s) : str{s} {} // required
constexpr MyStringView(const char* s, std::size_t size) : str{s, size} {} // required
constexpr bool empty() const { return str.empty(); } // required
constexpr std::size_t size() const { return str.size(); } // required
constexpr const char* data() const { return str.data(); } // required
constexpr const char& operator[](std::size_t i) const { return str[i]; } // required
constexpr void remove_prefix(std::size_t n) { str.remove_prefix(n); } // required
constexpr void remove_suffix(std::size_t n) { str.remove_suffix(n); } // required
constexpr int compare(MyStringView s) const { return str.compare(s.str); } // required
constexpr int compare(const char* s) const { return str.compare(s); }
private:
std::string_view str;
constexpr MyStringView(std::string_view s) : str{s} {}
};
#define NAMEOF_USING_ALIAS_STRING using string = MyString;
#define NAMEOF_USING_ALIAS_STRING_VIEW using string_view = MyStringView;
#include <nameof.hpp>
enum class Color { RED = 1, GREEN = 2, BLUE = 4 };
TEST_CASE("string") {
auto cr = nameof::nameof_enum_flag(Color::RED);
REQUIRE_FALSE(cr.empty());
REQUIRE(cr.compare("RED") == 0);
auto crg = nameof::nameof_enum_flag(static_cast<Color>(1 | 2));
REQUIRE_FALSE(crg.empty());
REQUIRE(crg.compare("RED|GREEN") == 0);
auto cn = nameof::nameof_enum_flag(Color{0});
REQUIRE(cn.empty());
REQUIRE(cn.size() == 0);
}
TEST_CASE("string_view") {
auto cr = nameof::nameof_enum(Color::RED);
REQUIRE_FALSE(cr.empty());
REQUIRE(cr.compare("RED") == 0);
auto cn = nameof::nameof_enum(Color{0});
REQUIRE(cn.empty());
REQUIRE(cn.size() == 0);
}

View file

@ -1,10 +0,0 @@
cmake_minimum_required(VERSION 3.8)
project(test_package CXX)
include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake)
conan_basic_setup(TARGETS)
add_executable(test_package test_package.cpp)
target_link_libraries(test_package PRIVATE CONAN_PKG::nameof)
set_target_properties(test_package PROPERTIES CXX_EXTENSIONS OFF)
target_compile_features(test_package PRIVATE cxx_std_17)

View file

@ -1,18 +0,0 @@
# -*- coding: utf-8 -*-
from conans import ConanFile, CMake, tools
import os
class TestPackageConan(ConanFile):
settings = "os", "compiler", "build_type", "arch"
generators = "cmake"
def build(self):
cmake = CMake(self)
cmake.configure()
cmake.build()
def test(self):
if not tools.cross_building(self.settings):
bin_path = os.path.join("bin", "test_package")
self.run(bin_path, run_environment=True)

View file

@ -1,19 +0,0 @@
#include <nameof.hpp>
#include <cstdlib>
struct SomeStruct {};
SomeStruct structvar;
int main() {
constexpr auto name = NAMEOF(structvar);
static_assert("structvar" == name);
std::string_view res1 = NAMEOF(structvar);
std::string_view res2 = NAMEOF(::structvar);
bool success = (res1 == "structvar") && (res2 == "structvar");
return success ? EXIT_SUCCESS : EXIT_FAILURE;
}