4

さまざまな POD タイプとカスタム クラス タイプに対して明示的にインスタンス化する、テンプレート化されたマトリックス クラスがあります。ただし、一部のメンバー関数は、そのようなカスタム型のいくつかでは意味がありません。例えば:

Matrix<int> LoadFile(....); // This makes sense
Matrix<My_custom_class> LoadFile(...); //This doesn't make sense in the context of the custom class

選択型のオブジェクトのLoadFile関数 (メンバー関数)のインスタンス化を防ぐことはできますか? これまでのところ、フレンド関数を作成し、そのインスタンス化を明示的に制御するMatrixことで問題を回避しました。しかし、が のメンバー関数であるLoadFile場合に、これを実行できるかどうかを知りたいです。LoadFileMatrix

4

5 に答える 5

4

最初の質問は、本当にこれを制御する必要があるかどうかです。を格納する行列でそのメンバー関数を呼び出すとどうなりますMy_custom_classか? メンバー関数が機能するように、クラス (またはテンプレート) でサポートを提供できますか?

特定の型に対してこれらのメンバー関数の使用を本当に禁止したい場合は、特殊化を使用して特定のインスタンス化をブロックできます。

template <typename T>
struct test {
   void foo() {}
};
template <>
inline void test<int>::foo() = delete;

またはstatic_assert、一般的な実装に s を追加して、どのタイプが許可または禁止されているかの前提条件を確認するだけですか?

template <typename T>
struct test {
   void foo() {
       static_assert(std::is_same<T,int>::value || std::is_same<T,double>::value,
                     "Only allowed for int and double");
       // regular code
   }
};
于 2013-03-26T01:49:52.650 に答える
2

std::enable_if、これは私が思いつくことができる最高のものです

template< typename T >
struct Matrix {
    template< typename T >
    Matrix< typename std::enable_if<std::is_integral<T>::value, T>::type >
        LoadFile() 
    {
        return Matrix<T>();
    }
};

Matrix<int> a;
Matrix<int> b = a.LoadFile<int>()

コンパイルのみを入力intし、他のタイプはそうではありません。

于 2013-03-26T02:03:08.017 に答える
1

選択タイプの Matrix オブジェクトの LoadFile 関数 (メンバー関数) のインスタンス化を防ぐことはできますか?

ここでの最善の策static_assertは、ブロックされた型でインスタンス化されたクラスのバージョンでメソッドを呼び出そうとすると、コンパイラ エラーが発生する を使用することです。std::enable_if、およびメソッド自体を選択的に「無効化」するその他のメソッドを使用するには、コンパイラ エラーを防ぐために、問題のメソッドの有無にかかわらず、クラスの部分的または完全な特殊化を作成する必要があります。たとえば、知る限り、次のことはできません。

template <typename T>
struct test
{
    static const bool value = false;
};

template<>
struct test<double>
{
    static const bool value = true;
};


template<typename T>
struct example
{
    void print() { cout << "Printing value from print()" << endl; }

    typename enable_if<test<T>::value, T>::type another_print() 
    { 
        cout << "Printing value from another_print()" << endl;
        return T(); 
    }
};

などをインスタンス化しようとするexample<int>と、オブジェクト型のインスタンス化の時点でコンパイラ エラーが発生します。単に電話example<int>::print()して大丈夫というわけではなく、電話を選択した場合にのみ問題が発生しますexample<int>::another_print()。のスペシャライゼーションでexample<T>問題を回避できますが、それは少し混乱する可能性があります。最初に推測static_assertされたように、問題の原因を説明するエンド ユーザーへの適切なメッセージと共に、a がおそらく最も扱いやすいケースでしょう。

コンパイラ エラーを作成すること目標であり、それを行うのは良いことです。メソッドのインスタンス化をブロックし、エンド ユーザーがそれを呼び出すことにした場合、いずれにしてもコンパイラ エラーが発生します。のないバージョンでstatic_assertは、クラスのユーザーがおそらく非常に冗長なコンパイラ エラー メッセージを解析しようとするため、多くの頭を悩ませることになりますstatic_assert

于 2013-03-26T01:44:48.027 に答える
1

選択した型のセットがコンパイル時にわかっていて、型エイリアス均一な初期化constexpr (gcc 4.7 など) をサポートするコンパイラで c++11 を使用している場合は、このようにコードを少しきれいにすることができます (から上記の前の例 yngum による):

template <bool Cond, class T = void>
using enable_if_t = typename std::enable_if<Cond, T>::type;

    template< typename T >
    struct Matrix {

    template< typename T >
    //std::is_integral has constexpr operator value_type() in c++11. This will work thanks to uniform init + constexpr. With the alias, no more need for typename + ::type
    Matrix<enable_if_t<std::is_integral<T>{}>>
    LoadFile() 
    {
        return Matrix<T>();
    }
};

Matrix<int> a;
Matrix<int> b = a.LoadFile<int>();

ただし、これらの機能は最近サポートされたばかりで、一部のコンパイラはまだサポートしていないため、このコードの互換性に注意してください。C++11 コンパイラ サポートの詳細については、こちらを参照してください

于 2013-03-26T12:10:19.677 に答える
0

( http://www.amazon.com/Modern-Design-Generic-Programming-Patterns/dp/0201704315 ) - Lokiの TypeLists を使用できる場合は、次のようなものを実装できます。

template<bool>
struct Static_Assert;

template<>
struct Static_Assert<true>{};

class B{};

template<typename T>
class A{
public:
  A(){
    Static_Assert< 0 == utils::HasType<T, TYPELIST_2(B,int) >::value >();
  }
};

次に、 HasType は次のようになります。

template<typename T, typename TList>
struct HasType{
  enum { value = 0+HasType< T, typename TList::Tail >::value };
};

template<typename T>
struct HasType< T, NullType >{
  enum { value = 0 };
};

template<typename T, typename U>
struct HasType< T, TypeList<T, U> >{
  enum { value = 1 };
};

リストに、テンプレート パラメータとして渡されないようにしたいクラスを追加できます。

于 2013-03-31T18:40:18.507 に答える