1

_base *から派生していないクラスでfooのコンストラクターを呼び出すときに、コンパイラーを叫ばせることができるようにしたいと思います。現在のコードでは、foo<_base*>自体のみが許可されています。簡単な解決策はありますか?

class _base
{
public:
    // ...
};

class _derived: public _base
{
public:
    // ...
};

template <typename T>
class foo
{
public:
    foo ()      { void TEMPLATE_ERROR; }
};

template <> foo<_base*>::foo () 
{
    // this is the only constructor
}

メインコード:

foo<_base*>    a;    // should work 
foo<_derived*> b;    // should work (but doesnt)
foo<int*>      c;    // should not work (and infact doesnt)
4

3 に答える 3

4

SFINAE (経由enable_if) と Boost のis_convertible型特性を使用します。

template <typename T, typename Enabled = void>
class foo
{
private:
    foo(); // Constructor declared private and not implemented.
};

template <typename T>
class foo<T, typename enable_if<is_convertible<T, _base*> >::type>
{
public:
    foo() { /* regular code */ }
};

(未テスト、このマシンに Boost がインストールされていません。)

于 2009-11-01T18:05:07.697 に答える
3

Boost を使用しない場合は、次のようなものを使用して、型へのポインターを別の型へのポインターに暗黙的にキャストできるかどうかを判断できます。

template <class Derived, class Base>
struct IsConvertible
{
    template <class T>
    static char test(T*);

    template <class T>
    static double test(...);

    static const bool value = sizeof(test<Base>(static_cast<Derived*>(0))) == 1;
};

コンパイル時にエラーをトリガーするために、valuefalse の場合にエラーを引き起こす式で使用できるようになりました。たとえば、負のサイズの配列を typedef します。

template <typename T>
class foo
{
public:
    foo ()
    {
        typedef T assert_at_compile_time[IsConvertible<T, _base>::value ? 1 : -1];
    }
};
于 2009-11-01T20:41:29.940 に答える
1

プロジェクトでブーストを使用していないことは理解していますが、その一部をコピーして貼り付けることができます。

ブーストを使用して、問題に対するより簡単な解決策を見つけました。

template <typename T>
class foo
{
public:
    foo () {
        BOOST_STATIC_ASSERT((boost::is_convertible<T,_base*>::value));
    }
};

追加のテンプレート パラメーターは必要なく、テンプレートの特殊化も必要ありません。ブースト1.40でテストしました。

于 2009-11-01T19:16:41.703 に答える