将 char 数组属性传递给模板方法

pass char array properly to templated method

我有一些带有枚举变量的 class,我想将该枚举字符串化。出于这个原因,我添加了 typeValue 和字符串化值。我还添加了单独的 class 来获取字符串化值,但我无法以正确的方式传递变量。 代码如下:

#include <iostream>
#include <string>
#include <algorithm>

#define stringify(name) #name

struct MyClass
{
    enum class TYPE
    {
        UNKNOWN = 0,
        CLIENT,
        SERVER
    };
    
    MyClass(TYPE t)
        :_type(t)
    {       
    }
    
    TYPE type()
    {
        return _type;
    }

    inline static const char* typeValue[10] =
    {
        stringify(TYPE::UNKNOWN),
        stringify(TYPE::CLIENT),
        stringify(TYPE::SERVER)
    };
    
private:
    TYPE _type;
};


struct EnumStringify
{
    /**
    * Get enum type string by value
    */
    template <class EnumType>
    static std::string getEnumTypeName(const EnumType& t, const char (*typeValues)[10])
    {
        std::string s(typeValues[static_cast<int>(t)]);
        return (s.size()) ? s.substr(s.find_last_of(":") + 1) : "";
    }
};

int main()
{
  MyClass a(MyClass::TYPE::CLIENT);
  std::cout << EnumStringify::getEnumTypeName<MyClass::TYPE>(a.type(), MyClass::typeValue).c_str();
}

发生错误:

main.cpp:55:90: error: no matching function for call to ‘EnumStringify::getEnumTypeName(MyClass::TYPE, const char* [10])’
   std::cout << EnumStringify::getEnumTypeName<MyClass::TYPE>(a.type(), MyClass::typeValue).c_str();
                                                                                          ^
main.cpp:45:21: note: candidate: template static std::string EnumStringify::getEnumTypeName(const EnumType&, const char (*)[10])
  static std::string getEnumTypeName(const EnumType& t, const char (*typeValues)[10])
                     ^~~~~~~~~~~~~~~
main.cpp:45:21: note:   template argument deduction/substitution failed:
main.cpp:55:90: note:   cannot convert ‘MyClass::typeValue’ (type ‘const char* [10]’) to type ‘const char (*)[10]’
   std::cout << EnumStringify::getEnumTypeName<MyClass::TYPE>(a.type(), MyClass::typeValue).c_str();

请帮我改正。也许 typedef 会更好?

两个问题:

  1. const char(*name)[] 定义指向 const char 数组的指针,而不是字符串。
  2. MyClass::typeValueconst char* (&)[10] 类型,因此不能隐式转换为指向该数组的指针。

这个有效:

class MyClass{
    //...
    constexpr static const char* typeValue[10] = {
        stringify(TYPE::UNKNOWN),
        stringify(TYPE::CLIENT),
        stringify(TYPE::SERVER)
    };
    
private:
    TYPE _type;
};


struct EnumStringify
{
    /**
    * Get enum type string by value
    */
    template <class EnumType>
    static std::string getEnumTypeName(const EnumType& t, const char* const (&typeValues )[10])
    {
        std::string s(typeValues[static_cast<int>(t)]);
        return (s.size()) ? s.substr(s.find_last_of(":") + 1) : "";
    }
};

我还添加了 constexpr 并通过 const 引用传递值,因为您不想更改它。

我的建议是使用 std::array,它减轻了传递数组的所有问题。

std::array解决方案

#include <iostream>
#include <string>
#include <algorithm>
#include <array>

#define stringify(name) #name

struct MyClass
{
    enum class TYPE
    {
        UNKNOWN = 0,
        CLIENT,
        SERVER
    };
    
    MyClass(TYPE t)
        :_type(t)
    {       
    }
    
    TYPE type()
    {
        return _type;
    }

    constexpr static auto typeValue = std::array{
        stringify(TYPE::UNKNOWN),
        stringify(TYPE::CLIENT),
        stringify(TYPE::SERVER)
    };
    
private:
    TYPE _type;
};

struct EnumStringify
{
    template <class EnumType, class Array>
    static std::string getEnumTypeName(const EnumType& t, const Array& array)
    {
        std::string s(array[static_cast<int>(t)]);
        return (s.size()) ? s.substr(s.find_last_of(":") + 1) : "";
    }
};

int main()
{
  MyClass a(MyClass::TYPE::CLIENT);
  std::cout << EnumStringify::getEnumTypeName(a.type(), MyClass::typeValue).c_str();
}

模板变量

如果我要编写这样的代码,我会使用模板变量,用户可以专门为他们自己的枚举提供字符串:

//

// "Stringify Library"
#define stringify(name) #name

struct MissingEnumTable{};
template<class Enum>
constexpr MissingEnumTable stringified_enum{};

template <class E>
static std::string getEnumTypeName(const E& t)
{
    static_assert(!std::is_same_v<decltype(stringified_enum<E>),MissingEnumTable>,
                  "Enum E is missing stringified_enum table specialization.");
    std::string s(stringified_enum<E>[static_cast<int>(t)]);
    return (s.size()) ? s.substr(s.find_last_of(":") + 1) : "";
}

// END

// Library user
//  - Provide strings for a custom array
enum class TYPE
{
    UNKNOWN = 0,
    CLIENT,
    SERVER
};

template<>
constexpr auto stringified_enum<TYPE> = std::array{
        stringify(TYPE::UNKNOWN),
        stringify(TYPE::CLIENT),
        stringify(TYPE::SERVER)
    };

int main()
{
  std::cout << getEnumTypeName(TYPE::UNKNOWN).c_str();
}