部分专业化时基于C++模板的"覆盖"等效?

vda*_*vid 6 c++ templates overriding partial-specialization

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

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

我想确保专业化尊重这个界面.

不幸的是,我可以使用不同的返回类型来专门化这个结构.例如,如果我部分专门返回bool而不是unsigned int,我希望得到编译器错误,但编译器似乎并不关心:

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

示例 @ Ideone.com

在上面的示例中,应该返回专用版本,2但是由于返回类型是bool,返回值将被转换true为然后显示为1.

为什么编译器会接受这个?

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

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

使用覆盖的解决方案(不编译,这很好)

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

另外,我知道问题会更简单,如果我可以部分专门化方法或者我可以依赖非部分专业化,但前者在C++ AFAIK中是不可能的,后者不包括我在程序中需要的情况.

bar*_*top 2

创建静态界面的一个好方法是使用奇怪的重复模板模式。在你的情况下,它看起来像这样:

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; }
};
Run Code Online (Sandbox Code Playgroud)

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

template<class Derived, class T, class U>
void test(const StaticInterface<Derived, T, U> &inter){
    inter(T(), U());
}
Run Code Online (Sandbox Code Playgroud)

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