1

これがばかげている場合は申し訳ありません。多くの同様の質問がありますが、実際にこの問題に対処しているものはないようです。それらはすべて少し異なります。

だから私が達成したいこと:テンプレートクラスを考えてくださいX<T>。ここで、そのテンプレートの特定のインスタンスに対して追加のコンストラクターが存在することを望みます。たとえば、ポインターの場合X<T*>です。のテンプレート仕様全体を作成したくはありません。これは、通常のテンプレートとまったく同じにする必要があるX<T*>ためです (そして、そのテンプレートは巨大であるため、コピー貼り付けはコードの複製の臭いがする可能性があります)。ただし、追加のコンストラクターがあるだけです。X<T*>また、これら 2 つの間にサブタイプの関係を確立したくないため、X<T*>継承元にしたくありません。X<T>これは可能ですか?私はこのように試しました:

template<T> class X{};

template<T> X<T*>::X(int i){...}

しかし、コンパイルされません。これはどういうわけか可能ですか?

4

2 に答える 2

5

SFINAEを使用して、次のようなことができます。

#include <iostream>
#include <type_traits>

template<class T> class X{
public:
    X(int i) {
        init();
    }
private:
    template<class U = T>
    typename std::enable_if<std::is_pointer<U>::value>::type init() {
        std::cout << "It's a pointer!\n";
    }

    template<class U = T>
    typename std::enable_if<!std::is_pointer<U>::value>::type init() {
        std::cout << "It's not a pointer!\n";
    }
};

int main() {
    X<int> a(1);
    X<int*> b(2);
}

どの出力:

It's not a pointer!
It's a pointer!

コンストラクターをオーバーロードしていませんが、必要なものを達成しています。

このコードを使用するには C++11 が必要であることに注意してください。

編集:さて、このコードはあなたが望むことを正確に行います:

#include <iostream>
#include <type_traits>

template<class T> class X{
public:
    template<class U = T, class enabler = typename std::enable_if<std::is_pointer<U>::value, T>::type>
    X(int i) {
        std::cout << "It's a pointer!\n";
    }

    template<class U = T, class enabler = typename std::enable_if<!std::is_pointer<U>::value, T*>::type>
    X() {
        std::cout << "It's not a pointer!\n";
    }
};

int main() {
    X<int> a;
    X<int*> b(2);
}

これは以前と同じように出力されます。これはあまり良い設計ではないことに注意してください。テンプレート引数に応じていくつかのコンストラクターを持つことは奇妙です。ただし、このコードは問題を解決します。

于 2012-06-15T14:22:06.890 に答える
0

これは、ブーストを使用するが C++11 を必要としないソリューションです。いずれの場合もX、単一の引数を取るコンストラクターがあります。がポインタの場合T、期待される引数はint. がポインターでない場合T、引数は呼び出し元がアクセスできない型です。

#include <boost/type_traits.hpp>

template < typename T >
class X
{
private:
  // Declare a private type that will be used to prevent a single-argument 
  // constructor from being callable when T is not a pointer.
  struct T_must_be_a_pointer;
public:
  // Branch at compile-time based on T:
  // - If T is a pointer, then declare the X( int ) constructor.
  // - If T is not a pointer, then declare X( T_must_be_a_pointer ) constructor.
  explicit X( typename boost::mpl::if_< boost::is_pointer< T >,
                                        int,
                                        T_must_be_a_pointer >::type i )
  {}
};

int main() {
    X<int> a();
    // Next line will fail to compile:
    // X<int> b(1);
    X<int*> c(2);
    return 0;
}
于 2012-06-15T15:17:14.117 に答える