【问题标题】:pass char array properly to templated method将 char 数组正确传递给模板方法
【发布时间】:2021-08-25 16:53:09
【问题描述】:

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

#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 会更好?

【问题讨论】:

  • 基于type 'const char [10]')在错误信息中输入'const char ()[10]',它看起来像const char (*typeValues)[10] 看起来太像一个函数指针数组(或类似的东西)。如果删除 (*typeValues) 周围的括号会发生什么?
  • 是的,没有括号它也可以。谢谢。但是 typedef 应该怎么做呢?

标签: c++ enums c++17


【解决方案1】:

两个问题:

  1. const char(*name)[] 定义了一个指向 const chars 数组的指针,而不是字符串。
  2. MyClass::typeValue 的类型为 const char* (&amp;)[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();
}

【讨论】:

  • 如果通过 typedef 定义 typeValue 和 getEnumTypeName?它看起来怎么样?
  • getEnumTypeName 是一个模板函数,不能定义类型,反正也没多大意义吧?它不是一个类型,它是一个函数(模板)。 typeValue 也不是类型。
  • 我的意思是用 typedef 定义const char* typeValue[10]
  • 当然,using type= const char*[10]; 有效,但std::array 是更安全的选择。
  • 是的,它按预期工作。非常感谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-04-15
  • 2021-09-09
  • 1970-01-01
  • 1970-01-01
  • 2014-04-03
  • 1970-01-01
相关资源
最近更新 更多