【问题标题】:Instantiate non-template class with templated constructor使用模板化构造函数实例化非模板类
【发布时间】:2019-03-06 19:28:30
【问题描述】:

我有一个小型 C++ 类,它包含一些基本类型的类型信息;简化版如下所示:

struct TypeInfo {
    TypeInfo(std::size_t elm_size, const std::string& type_name) : 
        elm_size(elm_size), 
        type_name(type_name)
    {}

    std::size_t elm_size;
    std::string type_name;    
}


TypeInfo double_info(sizeof double, "double");
TypeInfo int_info(sizeof int, "int");

这可行——但我希望能够基于普通 C++ 模板实例化 TypeInfo 对象;即这样的事情:

TypeInfo<double> double_info; // <- This does not work

因为这样的类不包含任何T - 它不是真正的模板类 - 而是一种方便的实例化方法。当 this 包含在真正模板化的函数中时:

void vector_operation(const std::vector<T>& data) {
    TypeInfo<T> type_info;  // <- This does not work!
}

如果我可以基于模板参数实例化TypeInfo 实例,那将是真正很有帮助的。因为我只需要涵盖少数基本类型 - float, double, intchar,我会非常乐意明确地专门化少数类型。

更新:@nathan_oliver 建议将类作为一个整体做成模板,然后使用sizeof(T) 确定元素大小。该解决方案的问题(如我所见) - 用户仍然需要提供 type_name 字符串(以及更多特定于类型的信息) - 我想专门化我需要的几种类型 - 然后完全指定:

template <typename T>
struct TypeInfo {
    TypeInfo();

    std::size_t elm_size;
    std::string type_name;
}

然后在.cpp文件中:

template<>
TypeInfo::TypeInfo<double>() {
     this->elm_size = sizeof(double);
     this->type_name = "double";
}


template<>
TypeInfo::TypeInfo<int>() {
    this->elm_size = sizeof(int);
    this->type_name = "int";
}

但这甚至不能编译:

type_info.cpp:46:5: error: 
invalid use of template-name ‘TypeInfo’ without an argument list
     TypeInfo::TypeInfo()

【问题讨论】:

  • 你有一个错字。 TypeInfo::TypeInfo&lt;double&gt;() 应该是 TypeInfo&lt;double&gt;::TypeInfo()
  • 另外,您不能将模板放入 cpp 文件中:stackoverflow.com/questions/495021/…
  • 谢谢——那个错字不是错字;它缺乏能力。我在 cpp 文件中有模板 specializations - 这应该可以吗?
  • 如果另一个翻译单元使用它,则 cpp 中的专业化将不起作用。所有模板代码都应该在一个头文件中。

标签: c++ templates


【解决方案1】:

如果您确实只对少数基本类型感兴趣,并且可以手动对其进行专门化,那么这似乎是一个不错的选择。

template <typename T>
struct TypeInfo; // default values could go here for un-specified types

template <>
struct TypeInfo<int> {
    const std::size_t elm_size = sizeof(T);
    const std::string type_name = "int";
}

// more specializations for double, char and float

然后您可以继续使用它,只需使用模板参数进行实例化即可。

如果TypeInfo 的不同实例是不同类型这一事实是一个问题,您可以使用一个函数,该函数返回一个公共TypeInfo 对象,并根据传递给函数的参数设置正确的值。

template <typename T>
TypeInfo get_type_info() {
    return TypeInfo{sizeof(T), "unknown"};
}

template <>
TypeInfo get_type_info<int>() {
    return TypeInfo{sizeof(T), "int"};
}

auto type_info = get_type_info<int>();

【讨论】:

    【解决方案2】:

    由于无法调用构造函数,因此无法将类构造函数设为模板并能够指定模板类型。

    您可以将类设为模板,并使用模板类型来获取类型的大小,而不是让用户提供它。那会给你

    template<typename T>
    struct TypeInfo {
        TypeInfo(const std::string& type_name) : 
            type_name(type_name)
        {}
    
        std::size_t elm_size = sizeof(T);
        std::string type_name;    
    };
    
    TypeInfo<double> double_info("double");
    TypeInfo<int> int_info("int");
    

    【讨论】:

    • 结合对我的编译错误的有用评论,这似乎成为最终解决方案;谢谢!
    【解决方案3】:

    另一种解决方案是使用辅助函数。

    struct TypeInfo {
        TypeInfo(std::size_t elm_size, const std::string& type_name) : 
            elm_size(elm_size), 
            type_name(type_name)
        {}
    
        std::size_t elm_size;
        std::string type_name;    
    };
    
    template <typename T>
    TypeInfo make_TypeInfo(const std::string& type_name)
    {
       return TypeInfo(sizeof(T), type_name);
    }
    

    并使用

    TypeInfo double_info = make_TypeInfo<double>("double");
    TypeInfo int_info = make_TypeInfo<int>("int");
    

    【讨论】:

    • 是的 - 我已经考虑过了
    【解决方案4】:

    您不能为构造函数指定模板参数。它们只能被推断出来。您可以向构造函数发送类型标记:

    template<typename> struct tag_t {};
    template<typename T> inline constexpr auto tag = tag_t<T>{}; 
    
    struct TypeInfo {
        template<typename T>
        TypeInfo(tag_t<T>) :
            elm_size{sizeof(T)},
            type_name{/* find a way to get name */} {}
    
        std::size_t elm_size;
        std::string type_name;  
    };
    
    TypeInfo double_info{tag<double>};
    TypeInfo int_info{tag<int>};
    

    您必须找到一种从模板参数中获取类型名称的方法。一些库是为此而存在的,例如ctti

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2013-02-09
      • 2016-07-02
      • 2019-04-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多