This commit is contained in:
Neargye 2018-04-04 17:19:02 +05:00
parent 425046ecb6
commit c9024c9f1c
10 changed files with 297 additions and 56 deletions

View file

@ -1,4 +1,5 @@
dist: trusty
sudo: required
language: cpp

View file

@ -1,13 +1,11 @@
cmake_minimum_required(VERSION 3.6.4)
cmake_minimum_required(VERSION 3.6)
project(nameof)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
add_compile_options(-pedantic)
add_compile_options(-Wall)
add_compile_options(-Wextra)
add_compile_options(-Wall -Wextra -pedantic)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
add_compile_options(/W4)
endif()

View file

@ -46,8 +46,8 @@ NAMEOF(SomeEnum::GREEN) -> "GREEN"
* Name of type
```cpp
NAMEOF_TYPE(int[]) -> "int[]"
NAMEOF_TYPE(std::string) -> "string"
NAMEOF(int[]) -> "int[]"
NAMEOF(std::string) -> "string"
```
* Constexpr
@ -66,7 +66,7 @@ void f() {
int i;
NAMEOF(i); -> "i"
NAMEOF(iii); -> error identifier "iii" is undefined
NAMEOF_TYPE(std::stringgg) -> error namespace "std" has no member "stringgg"
NAMEOF(std::stringgg) -> error namespace "std" has no member "stringgg"
}
```
@ -105,11 +105,20 @@ void f() {
## Remarks
If you need to get the fully-qualified name, you can use the NAMEOF_FULL(). For example:
* If you need to get the fully-qualified name, you could use the NAMEOF_FULL().
```cpp
NAMEOF_FULL(someVar.SomeField) -> "someVar.SomeField"
NAMEOF_FULL(&SomeStruct::SomeMethod2) -> "&SomeStruct::SomeMethod2"
NAMEOF_FULL(std::string) -> "std::string"
```
* If compiling without RTTI, you need use the NAMEOF_TYPE() for get name of type.
```cpp
NAMEOF_TYPE(int[]) -> "int[]"
NAMEOF_TYPE(std::string) -> "string"
NAMEOF_TYPE_FULL(std::string) -> "std::string"
```

View file

@ -1,9 +1,5 @@
version: "{branch} #{build}"
branches:
only:
- master
image: Visual Studio 2017
platform: x64

View file

@ -1,5 +1,7 @@
include_directories(${CMAKE_SOURCE_DIR}/src)
set(SRC example.cpp)
set(SOURCE_EXAMPLE
${CMAKE_SOURCE_DIR}/src/nameof.hpp
example.cpp)
add_executable(${PROJECT_NAME}_example ${SRC})
add_executable(${PROJECT_NAME}_example ${SOURCE_EXAMPLE})

View file

@ -77,10 +77,18 @@ void TestCase1() {
std::cout << NAMEOF(&SomeStruct::SomeMethod2) << std::endl; // SomeMethod2
std::cout << NAMEOF(SomeMethod3) << std::endl; // SomeMethod3
std::cout << NAMEOF(int[]) << std::endl; // int[]
std::cout << NAMEOF(SomeStruct) << std::endl; // SomeStruct
std::cout << NAMEOF(Long::LL) << std::endl; // LL
std::cout << NAMEOF(volatile const int) << std::endl; // const volatile int
// If no RTTI, use NAMEOF_TYPE().
#if !defined(__GXX_RTTI) && !defined(_CPPRTTI) && !defined(__RTTI) && !defined(__INTEL_RTTI__)
std::cout << NAMEOF_TYPE(int[]) << std::endl; // int[]
std::cout << NAMEOF_TYPE(SomeStruct) << std::endl; // SomeStruct
std::cout << NAMEOF_TYPE(Long::LL) << std::endl; // LL
std::cout << NAMEOF_TYPE(const volatile int) << std::endl; // const volatile int
std::cout << NAMEOF_TYPE(volatile const int) << std::endl; // const volatile int
#endif
std::cout << NAMEOF_FULL(someVar.SomeField) << std::endl; // someVar.SomeField
std::cout << NAMEOF_FULL(&SomeStruct::SomeMethod2) << std::endl; // &SomeStruct::SomeMethod2

View file

@ -1,5 +1,5 @@
// nameof() c++11 https://github.com/Neargye/nameof
// Vesion 0.1.5
// Vesion 0.2.0
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// Copyright (c) 2016, 2018 Daniil Goncharov <neargye@gmail.com>.
@ -25,31 +25,61 @@
#pragma once
#include <cstddef>
namespace nameof {
#define NAMEOF_RAW_(x) #x
#define NAMEOF_RAW(x) NAMEOF_RAW_(x)
namespace nameof {
namespace detail {
inline constexpr bool IsLexeme(const char s) {
return (s == '.' || s == '>' || s == ':' || s == '&' || s == '*' ||
s == '+' || s == '~' || s == '-' || s == '!');
}
}
}
template <typename T, std::size_t N>
inline constexpr const char* Nameof(const char(&name)[N], const std::size_t length = N) {
return length == 0 ? name : IsLexeme(name[length - 1])
#if defined(__GXX_RTTI) || defined(_CPPRTTI) || defined(__RTTI) || defined(__INTEL_RTTI__)
#include <typeinfo>
namespace nameof {
inline constexpr const char* Nameof(const char* name, const std::size_t length, const std::size_t) {
return length == 0 ? name : detail::IsLexeme(name[length - 1])
? &name[length]
: Nameof(name, length - 1, 0);
}
}
// Used to obtain the string name of a variable, type, function and etc.
#define NAMEOF(name) nameof::Nameof(NAMEOF_RAW(name), sizeof(NAMEOF_RAW(name)) / sizeof(char) - 1, sizeof(typeid(name)))
// Used to obtain the string full name of a variable, type, function and etc.
#define NAMEOF_FULL(name) nameof::Nameof(NAMEOF_RAW(name), 0, sizeof(typeid(name)))
// Alias
#define NAMEOF_TYPE(type) NAMEOF(type)
#define NAMEOF_TYPE_FULL(type) NAMEOF_FULL(type)
#else
namespace nameof {
template <typename T>
inline constexpr const char* Nameof(const char* name, const std::size_t length) {
return length == 0 ? name : detail::IsLexeme(name[length - 1])
? &name[length]
: Nameof<T>(name, length - 1);
}
}
#define NAMEOF_RAW_(x) #x
#define NAMEOF_RAW(x) NAMEOF_RAW_(x)
// Used to obtain the string name of a variable, function and etc.
#define NAMEOF(name) nameof::Nameof<decltype(name)>(NAMEOF_RAW(name))
#define NAMEOF(name) nameof::Nameof<decltype(name)>(NAMEOF_RAW(name), sizeof(NAMEOF_RAW(name)) / sizeof(char) - 1)
// Used to obtain the string full name of a variable, function and etc.
#define NAMEOF_FULL(name) nameof::Nameof<decltype(name)>(NAMEOF_RAW(name), 0)
// Used to obtain the string name of a type.
#define NAMEOF_TYPE(type) nameof::Nameof<type>(NAMEOF_RAW(type))
#define NAMEOF_TYPE(type) nameof::Nameof<type>(NAMEOF_RAW(type), sizeof(NAMEOF_RAW(type)) / sizeof(char) - 1)
// Used to obtain the string full name of a type.
#define NAMEOF_TYPE_FULL(type) nameof::Nameof<type>(NAMEOF_RAW(type), 0)
#endif

View file

@ -1,8 +1,13 @@
include_directories(${CMAKE_SOURCE_DIR}/src)
include_directories(3rdparty/Catch2)
include_directories(3rdparty/Catch2)
include_directories(${CMAKE_SOURCE_DIR}/src)
set(SRC test.cpp)
add_executable(${PROJECT_NAME}_test test.cpp)
add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
add_executable(${PROJECT_NAME}_test ${SRC})
add_test(NAME ${PROJECT_NAME}_test COMMAND ${PROJECT_NAME}_test)
add_executable(${PROJECT_NAME}_test_no_rtti test_no_rtti.cpp)
if((CMAKE_CXX_COMPILER_ID MATCHES "GNU") OR (CMAKE_CXX_COMPILER_ID MATCHES "Clang"))
target_compile_options(${PROJECT_NAME}_test_no_rtti PUBLIC -fno-rtti)
elseif(CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
target_compile_options(${PROJECT_NAME}_test_no_rtti PUBLIC /GR-)
endif()
add_test(NAME ${PROJECT_NAME}_test_no_rtti COMMAND ${PROJECT_NAME}_test_no_rtti)

View file

@ -65,12 +65,12 @@ TEST_CASE("constexpr") {
}
SECTION("NAMEOF_TYPE") {
constexpr auto n = NAMEOF_TYPE(std::string);
constexpr auto n = NAMEOF(std::string);
REQUIRE(std::strcmp(n, "string") == 0);
}
SECTION("NAMEOF_TYPE_FULL") {
constexpr auto n = NAMEOF_TYPE_FULL(std::string);
constexpr auto n = NAMEOF_FULL(std::string);
REQUIRE(std::strcmp(n, "std::string") == 0);
}
}
@ -100,6 +100,26 @@ TEST_CASE("NAMEOF") {
REQUIRE(std::strcmp(NAMEOF(!intValue), "intValue") == 0);
}
SECTION("NAMEOF_TYPE") {
REQUIRE(std::strcmp(NAMEOF(int[]), "int[]") == 0);
REQUIRE(std::strcmp(NAMEOF(int[]), NAMEOF_TYPE(int[])) == 0);
REQUIRE(std::strcmp(NAMEOF(int), "int") == 0);
REQUIRE(std::strcmp(NAMEOF(int), NAMEOF_TYPE(int)) == 0);
REQUIRE(std::strcmp(NAMEOF(const volatile int[]), "const volatile int[]") == 0);
REQUIRE(std::strcmp(NAMEOF(const volatile int[]), NAMEOF_TYPE(const volatile int[])) == 0);
REQUIRE(std::strcmp(NAMEOF(std::string), "string") == 0);
REQUIRE(std::strcmp(NAMEOF(std::string), NAMEOF_TYPE(std::string)) == 0);
REQUIRE(std::strcmp(NAMEOF(SomeStruct), "SomeStruct") == 0);
REQUIRE(std::strcmp(NAMEOF(SomeStruct), NAMEOF_TYPE(SomeStruct)) == 0);
REQUIRE(std::strcmp(NAMEOF(Long::LL), "LL") == 0);
REQUIRE(std::strcmp(NAMEOF(Long::LL), NAMEOF_TYPE(Long::LL)) == 0);
}
SECTION("NAMEOF_FUNCTION") {
REQUIRE(std::strcmp(NAMEOF(someVar.SomeMethod1()), "SomeMethod1()") == 0);
REQUIRE(std::strcmp(NAMEOF(&SomeStruct::SomeMethod2), "SomeMethod2") == 0);
@ -112,17 +132,6 @@ TEST_CASE("NAMEOF") {
}
}
TEST_CASE("NAMEOF_TYPE") {
SECTION("NAMEOF_TYPE") {
REQUIRE(std::strcmp(NAMEOF_TYPE(int[]), "int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(int), "int") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(const volatile int[]), "const volatile int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(std::string), "string") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(SomeStruct), "SomeStruct") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(Long::LL), "LL") == 0);
}
}
TEST_CASE("NAMEOF_FULL") {
SomeStruct someVar;
Long otherVar;
@ -148,6 +157,27 @@ TEST_CASE("NAMEOF_FULL") {
REQUIRE(std::strcmp(NAMEOF_FULL(!intValue), "!intValue") == 0);
}
SECTION("NAMEOF_TYPE_FULL") {
REQUIRE(std::strcmp(NAMEOF_FULL(int[]), "int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(int[]), NAMEOF_TYPE_FULL(int[])) == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(int), "int") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(int), NAMEOF_TYPE_FULL(int)) == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(const volatile int[]), "const volatile int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(const volatile int[]), NAMEOF_TYPE_FULL(const volatile int[])) == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(std::string), "std::string") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(std::string), NAMEOF_TYPE_FULL(std::string)) == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(SomeStruct), "SomeStruct") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(SomeStruct), NAMEOF_TYPE_FULL(SomeStruct)) == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(Long::LL), "Long::LL") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(Long::LL), NAMEOF_TYPE_FULL(Long::LL)) == 0);
}
SECTION("NAMEOF_FUNCTION_FULL") {
REQUIRE(std::strcmp(NAMEOF_FULL(someVar.SomeMethod1()), "someVar.SomeMethod1()") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(&SomeStruct::SomeMethod2), "&SomeStruct::SomeMethod2") == 0);
@ -160,14 +190,3 @@ TEST_CASE("NAMEOF_FULL") {
}
}
TEST_CASE("NAMEOF_TYPE_FULL") {
SECTION("NAMEOF_TYPE_FULL") {
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(int[]), "int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(const volatile int[]), "const volatile int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(Long::LL), "Long::LL") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(std::string), "std::string") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(SomeStruct), "SomeStruct") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(Long::LL), "Long::LL") == 0);
}
}

173
test/test_no_rtti.cpp Normal file
View file

@ -0,0 +1,173 @@
// nameof() c++11 test_no_rtti
//
// Licensed under the MIT License <http://opensource.org/licenses/MIT>.
// Copyright (c) 2018 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.
#if defined(__GXX_RTTI) || defined(_CPPRTTI) || defined(__RTTI) || defined(__INTEL_RTTI__)
#error "need test case with no rtti"
#endif
#define CATCH_CONFIG_MAIN
#include <catch.hpp>
#include <nameof.hpp>
#include <cstring>
#include <string>
#include <iostream>
struct SomeStruct {
int SomeField;
void SomeMethod1() { std::cout << "No called!" << std::endl; }
int SomeMethod2() {
std::cout << "No called!" << std::endl;
return 1;
}
};
void SomeMethod3() { std::cout << "No called!" << std::endl; }
struct Long {
struct LL {
int LLLField;
};
LL LLField;
};
int someVar = 0;
enum class Color { RED, GREEN, BLUE };
TEST_CASE("constexpr") {
SomeStruct someVar;
SECTION("NAMEOF") {
constexpr auto n = NAMEOF(someVar);
REQUIRE(std::strcmp(n, "someVar") == 0);
}
SECTION("NAMEOF_FULL") {
constexpr auto n = NAMEOF_FULL((&someVar)->SomeField);
REQUIRE(std::strcmp(n, "(&someVar)->SomeField") == 0);
}
SECTION("NAMEOF_TYPE") {
constexpr auto n = NAMEOF_TYPE(std::string);
REQUIRE(std::strcmp(n, "string") == 0);
}
SECTION("NAMEOF_TYPE_FULL") {
constexpr auto n = NAMEOF_TYPE_FULL(std::string);
REQUIRE(std::strcmp(n, "std::string") == 0);
}
}
TEST_CASE("NAMEOF") {
SomeStruct someVar;
Long otherVar;
int intValue;
SomeStruct* ptrVar;
SomeStruct** ptrptrVar;
SECTION("NAMEOF_VARIABLE") {
REQUIRE(std::strcmp(NAMEOF(someVar), "someVar") == 0);
REQUIRE(std::strcmp(NAMEOF(someVar.SomeField), "SomeField") == 0);
REQUIRE(std::strcmp(NAMEOF((&someVar)->SomeField), "SomeField") == 0);
REQUIRE(std::strcmp(NAMEOF(::someVar), "someVar") == 0);
REQUIRE(std::strcmp(NAMEOF(otherVar.LLField.LLLField), "LLLField") == 0);
REQUIRE(std::strcmp(NAMEOF(&someVar), "someVar") == 0);
REQUIRE(std::strcmp(NAMEOF(ptrVar), "ptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF(*ptrVar), "ptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF(ptrptrVar), "ptrptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF(*ptrptrVar), "ptrptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF(**ptrptrVar), "ptrptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF(+intValue), "intValue") == 0);
REQUIRE(std::strcmp(NAMEOF(-intValue), "intValue") == 0);
REQUIRE(std::strcmp(NAMEOF(~intValue), "intValue") == 0);
REQUIRE(std::strcmp(NAMEOF(!intValue), "intValue") == 0);
}
SECTION("NAMEOF_TYPE") {
REQUIRE(std::strcmp(NAMEOF_TYPE(int[]), "int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(int), "int") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(const volatile int[]), "const volatile int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(std::string), "string") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(SomeStruct), "SomeStruct") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE(Long::LL), "LL") == 0);
}
SECTION("NAMEOF_FUNCTION") {
REQUIRE(std::strcmp(NAMEOF(someVar.SomeMethod1()), "SomeMethod1()") == 0);
REQUIRE(std::strcmp(NAMEOF(&SomeStruct::SomeMethod2), "SomeMethod2") == 0);
REQUIRE(std::strcmp(NAMEOF(SomeMethod3), "SomeMethod3") == 0);
}
SECTION("NAMEOF_ENUM") {
REQUIRE(std::strcmp(NAMEOF(Color::RED), "RED") == 0);
REQUIRE(std::strcmp(NAMEOF(Color::BLUE), "BLUE") == 0);
}
}
TEST_CASE("NAMEOF_FULL") {
SomeStruct someVar;
Long otherVar;
int intValue;
SomeStruct* ptrVar;
SomeStruct** ptrptrVar;
SECTION("NAMEOF_VARIABLE_FULL") {
REQUIRE(std::strcmp(NAMEOF_FULL(someVar), "someVar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(someVar.SomeField), "someVar.SomeField") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL((&someVar)->SomeField), "(&someVar)->SomeField") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(::someVar), "::someVar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(otherVar.LLField.LLLField), "otherVar.LLField.LLLField") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(&someVar), "&someVar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(ptrVar), "ptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(*ptrVar), "*ptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(ptrptrVar), "ptrptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(*ptrptrVar), "*ptrptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(**ptrptrVar), "**ptrptrVar") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(+intValue), "+intValue") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(-intValue), "-intValue") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(~intValue), "~intValue") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(!intValue), "!intValue") == 0);
}
SECTION("NAMEOF_TYPE_FULL") {
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(int[]), "int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(const volatile int[]), "const volatile int[]") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(std::string), "std::string") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(SomeStruct), "SomeStruct") == 0);
REQUIRE(std::strcmp(NAMEOF_TYPE_FULL(Long::LL), "Long::LL") == 0);
}
SECTION("NAMEOF_FUNCTION_FULL") {
REQUIRE(std::strcmp(NAMEOF_FULL(someVar.SomeMethod1()), "someVar.SomeMethod1()") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(&SomeStruct::SomeMethod2), "&SomeStruct::SomeMethod2") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(SomeMethod3), "SomeMethod3") == 0);
}
SECTION("NAMEOF_ENUM_FULL") {
REQUIRE(std::strcmp(NAMEOF_FULL(Color::RED), "Color::RED") == 0);
REQUIRE(std::strcmp(NAMEOF_FULL(Color::BLUE), "Color::BLUE") == 0);
}
}