我有一个模板类/结构,如下所示:
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中是不可能的,而后者不能满足我需要的情况在我的程序中。
答案 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());
}
否则,派生运算符将被选为首选。