局部专业化时基于C ++模板的“替代”等效项?

时间:2018-08-09 09:19:31

标签: c++ templates override partial-specialization

我有一个模板类/结构,如下所示:

template <typename T, typename U>
struct S
{
    unsigned int operator()(T t, U u) const;
};

我想确保专业化对此接口的尊重。

不幸的是,我可以使用其他返回类型来专门化此结构。例如,如果我部分专业化地返回bool而不是unsigned int,那么我期望得到一个编译器错误,但是编译器似乎并不在意:

template <typename T>
struct S<T,nullptr_t>
{
    bool operator()(T t, nullptr_t u) const { return 2; }
};

Example @ Ideone.com

在上面的示例中,特殊版本应该返回2,但是由于返回类型为bool,因此返回值将转换为true,然后显示为{{ 1}}。

为什么编译器会接受呢?

如何防止程序员使用错误的返回类型(甚至错误的参数)来专门化模板?

我知道我可以通过基本模板类/结构中的虚拟方法实现我想要的,并在子级中使用1关键字:

Solution with override(不编译,很好)

但是拥有虚拟方法肯定会创建一个虚拟表,我想尽可能避免这种情况,特别是因为在运行时不需要虚拟表时。除非有一个技巧可以在不构建虚拟表的情况下做到这一点?

此外,我知道如果我可以部分专业化方法或者我可以依赖非部分专业化,那么问题会更简单,但是前者在C ++ AFAIK中是不可能的,而后者不能满足我需要的情况在我的程序中。

1 个答案:

答案 0 :(得分:1)

创建静态接口的一种好方法是使用curiously recurring template pattern。在您的情况下,它看起来像这样:

template<class Derived, class T, class U>
constexpr bool MyTrait = std::is_same<unsigned int, decltype(std::declval<Derived>()(std::declval<T>(), std::declval<U>()))>::value;

template <typename Derived, class T, class U>
struct StaticInterface
{

    unsigned int operator()(T t, U u) const{
        static_assert( MyTrait<Derived, T, U>, "errr" );

        return (*static_cast<const Derived *>(this))(std::forward<T>(t), std::forward<U>(u));
    }
};

template <typename T, typename U>
struct S : StaticInterface<S<T, U>, T, U>
{
    unsigned int operator()(T t, U u) const{ /* some implementation */}
};

template <typename T>
struct S<T, std::nullptr_t> : StaticInterface<S<T, std::nullptr_t>, T, std::nullptr_t>
{
    bool operator()(T t, std::nullptr_t u) const { return 2; }
};

要使其正常工作,必须通过如下接口完成函数调用:

template<class Derived, class T, class U>
void test(const StaticInterface<Derived, T, U> &inter){
    inter(T(), U());
}

否则,派生运算符将被选为首选。