27

テンプレート化された型がプレーンな古いデータである場合にのみ正しく動作する C++ テンプレート クラスがあります。何かを行うコンストラクターを持つものはすべて正しく機能しません。

とにかく誰かがそうしようとしたときに、コンパイル時または実行時の警告をどうにかして取得したいと思います。

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

//this should be fine
myclass<int> b;

これを行うためのトリックはありますか?

4

6 に答える 6

38
#include <type_traits>

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

    // stuff here...
};

テンプレート パラメータとして POD 以外の型を渡すと、上記ではコンパイル エラーが発生します。<type_traits>このソリューションでは、ヘッダーとstatic_assertキーワードに C++11 が必要です。

編集: コンパイラが 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...
};
于 2013-10-03T08:15:41.027 に答える
11

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
}
于 2013-10-03T08:16:19.310 に答える
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!
}

定義から2番目のテンプレート引数を削除し、myclass代わりに他の人が提案したように、

  static_assert(std::is_pod<T>::value, "POD expected for T");

クラス内の 2 行目は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>

あなたの周りの全員が C++11 に流暢でない限り。

実生活では、T がコメント テキストとコメント テキストの両方で POD でなければならない理由static_assertを説明することをお勧めします。

于 2013-10-03T09:38:38.010 に答える
4

C++11 を持っていない場合

対象の POD タイプが限定されている場合 ( intfloat、...)、実装を.cppファイルに入れ、そのタイプに対して明示的にインスタンス化できます。

.hファイル:

template <typename T>
class myclass
{
    T data;
public:
    void func();
};

.cppファイル:

#include "myclass.h"

template <typename T>
void myclass<T>::func()
{
}

template class myclass<float>;
template class myclass<int>;
template class myclass<char>;
...

その後、myclassそれらのタイプでのみ使用でき、他のタイプで中断します。

于 2013-10-03T08:19:44.517 に答える
0

type_traits と static_assert を使用すると、非常に簡単です。

#include <type_traits>

struct A{
};
struct B{
    virtual ~B(){}
};

template< class T >
struct MyClass
{
    static_assert( std::is_pod<T>::value, "not a POD" );
};

int main()
{
    MyClass<A> a;
    //MyClass<B> b; -- break, cause not a POD
}
于 2013-10-03T08:20:40.553 に答える