将c ++模板使用限制为POD类型

Luc*_*jer 24 c++ templates type-traits

我有一个c ++模板类,只有在模板化类型是普通旧数据时才能正常运行.任何具有执行任何操作的构造函数的东西都无法正常工作.

无论如何,当有人试图这样做时,我想以某种方式获得编译时或运行时警告.

//this should generate error
myclass<std::string> a;

//this should be fine
myclass<int> b;
Run Code Online (Sandbox Code Playgroud)

有这个诀窍吗?

Sim*_*ple 37

#include <type_traits>

template<typename T>
class myclass
{
    static_assert(std::is_pod<T>::value, "T must be POD");

    // stuff here...
};
Run Code Online (Sandbox Code Playgroud)

如果将非POD类型作为模板参数传递,则上述操作将导致编译错误.此解决方案需要C++ 11作为<type_traits>标头和static_assert关键字.

编辑:如果您的编译器支持TR1(大多数),您也可以在C++ 03中实现它:

#include <tr1/type_traits>

template<typename T>
class myclass
{
    static char T_must_be_pod[std::tr1::is_pod<T>::value ? 1 : -1];

    // stuff here...
};
Run Code Online (Sandbox Code Playgroud)

  • @julien简单地说,按照你的链接:"如果没有编译器的一些(尚未指定的)帮助,`is_pod`永远不会报告类或结构是POD;如果可能是次优的,这总是安全的." 因此,它可以访问各种不同的,预标准的,不受支持的功能.如果不存在合适的特征,则盲目地返回`false_type`. (4认同)
  • @Potatoswatter,你也可以使用[`boost :: is_pod`](http://www.boost.org/doc/libs/1_54_0/libs/type_traits/doc/html/boost_typetraits/reference/is_pod.html) (2认同)

mag*_*gor 10

如果你有C++ 11支持,std :: is_pod应该完全符合你的需要.将它与std :: enable_if一起使用或与标签分配一起使用.例如这样的事情:

template <typename T, typename Enable = void>
class Test;

template<typename T>
class Test<T, typename std::enable_if<std::is_pod<T>::value, void>::type>
{};

int main() {
    Test<int> t1;
    //Test<std::string> t2; <-this will not compile
}
Run Code Online (Sandbox Code Playgroud)


Vas*_*rov 6

虽然static_assert在大多数情况下可能就足够了,但使用enable_if和标签调度可以通过SFINAE的方式为您的班级用户提供更大的灵活性.考虑:

#include <type_traits>
#include <string>
#include <iostream>
template <typename T,
    class=typename std::enable_if< std::is_pod<T>::value >::type>
struct myclass
{
    typedef T value_type;
    T data;
};

template <typename T>
void enjoy(T)
{
    std::cout << "Enjoying T!" << std::endl;
}

template <typename T>
void enjoy(typename myclass<T>::value_type)
{
    std::cout << "Enjoying myclass<T>::value_type!" << std::endl;
}

int main()
{
    enjoy<int>(int()); // prints: Enjoying myclass<T>::value_type!
    enjoy<std::string>(std::string()); // SFINAE at work - prints: enjoying T!
    myclass<int> i; // compiles OK
    //myclass<std::string> s; // won't compile - explicit instantiation w/non-POD!
}
Run Code Online (Sandbox Code Playgroud)

现在,如果从myclass定义中删除第二个模板参数,而不像其他人建议的那样,添加一个

  static_assert(std::is_pod<T>::value, "POD expected for T");
Run Code Online (Sandbox Code Playgroud)

在类中,第二行将main()无法编译,触发static_assert.

也就是说,来自static_assert失败者的错误对人类观察者来说更加友好enable_if.所以,如果static_assert适合你,那就去吧.否则,如果您确实需要对类的泛型编程更友好,请考虑添加解释性注释enable_if:

 // POD expected for T
 class=typename std::enable_if< std::is_pod<T>::value >::type>
Run Code Online (Sandbox Code Playgroud)

除非你周围的人都是C++ 11流利的.

在现实生活中,解释为什么 T必须是POD static_assert以及评论文本都是一个好主意.