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 (via enable_if) 和 Boost 的is_convertibletype trait

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;
};

为了让它在编译时触发错误,您现在可以value在表达式中使用如果它是假的就会导致错误,例如 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

我了解您没有在项目中使用 boost,但也许您可以复制粘贴其中的某些部分。

我使用 boost 找到了一个更简单的解决方案:

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

它不需要额外的模板参数,也不需要模板专业化。我用 boost 1.40 对其进行了测试。

于 2009-11-01T19:16:41.703 回答