作为理解C 0x的练习,我试图创建一个包含某些模板化类型指针的C类:
template <typename T> class Wrapper { T *t; /* ... */ };
在Wrapper类中,我想公开T可以通过Wrapper类实现的任何重载操作符.包装器本身只是将函数调用转发给底层的t对象.
template <typename U> auto operator+(U &u) -> decltype (*t + u) { return *t + u; }
问题在于我不希望Wrapper暴露T可能无法实现的运算符.例如,如果T没有实现运算符,那么Wrapper也不应该公开运算符.
在运算符(和任何二元运算)的情况下,一切都运行,因为运算符必然成为模板函数,因此仅在我们尝试调用时实例化,例如Wrapper :: operator.
然而,在一元运算符(例如)的情况下,没有明确的方法来保护运算符,以便如果T实现运算符则实例化它.例如,这个类中的运算符的天真实现
auto operator++() -> decltype(++(*t)) { return ++(*t); }
无法编译不支持operator()的T.
根据我对标准的理解,如果我们有以下使用Wrapper的代码
class X { }; Wrapper<X> w;
我们将实例化Wrapper和Wrapper :: operator()的声明,但不是它的定义,除非我们调用它(或显式实例化它).通常情况下这是可以的,因为X ::运算符的使用仅出现在Wrapper :: operator()的定义中.但是,由于decltype,我们在声明中使用X ::运算符,以便typechecker检查是否存在X ::运算符,从而失败.
我们可以定义operator()(通常是任何使用decltype的转发函数)和实例化的属性iff底层对象是否也支持operator()?或者给出模板实例化和decltype的语义,这是不可能完成的?
解决方法
您可以将运算符声明为非成员模板:
template <typename T> auto operator++(Wrapper<T>& arg) -> decltype(++*arg.t) { return ++*arg.t; }