作为理解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没有实现operator +,那么Wrapper也不应该公开operator +。
在operator +(和任何二进制操作)的情况下,一切都运行,因为运算符必然成为模板函数,因此只在我们尝试调用时实例化,例如,Wrapper :: operator +。
然而,在一元运算符(例如,++)的情况下,没有明确的方法来保护运算符,以便在tf实现operator ++时实例化它。例如,本类
中的operator ++的朴素实现auto operator++() -> decltype(++(*t)) {
return ++(*t);
}
无法为不支持operator ++()的T编译。
根据我对标准的理解,如果我们有以下使用Wrapper的代码
class X { };
Wrapper<X> w;
除非我们调用它(或显式地实例化它),否则我们将实例化Wrapper和Wrapper :: operator ++()的声明而不是它的定义。通常情况下这是可以的,因为X :: operator ++的使用仅出现在Wrapper :: operator ++()的定义中。但是,由于decltype,我们在声明中使用X :: operator ++,以便typechecker检查是否存在X :: operator ++,从而失败。
如果底层对象也支持operator ++(),我们可以定义operator ++()(通常是任何使用decltype的转发函数)和实例化它的属性吗?或者给出模板实例化和decltype的语义,这是不可能完成的?
答案 0 :(得分:5)
您可以将运算符声明为非成员模板:
template <typename T>
auto operator++(Wrapper<T>& arg) -> decltype(++*arg.t) {
return ++*arg.t;
}
答案 1 :(得分:4)
您也可以使用默认模板参数进行操作,只是为了使操作符的操作数相互依赖
template<typename Trick = T>
auto operator++() -> decltype(++(static_cast<Trick&>(*t))) {
return ++(*t);
}
也许在
之间有辅助功能template<typename /* Ignored */, typename T> T &&id(T &&t) {
return std::forward<T>(t);
}
template<typename Void = void>
auto operator++() -> decltype(++(*id<Void>(t))) {
return ++(*t);
}
答案 2 :(得分:2)
如果你能弄清楚如何在操作员签名中使用std::enable_if
,这里有一个元函数来检查是否存在例如operator->
。 #include <type_traits>
template<typename T, typename R>
inline R* has_deref_opr_sfinae_impl_helper(R (T::*)()) { return 0; }
template<typename T, typename R>
inline R* has_deref_opr_sfinae_impl_helper(R (T::*)() const) { return 0; }
template<
typename T,
bool IsPointer =
std::is_pointer<T>::value &&
!std::is_same<
typename std::remove_cv<
typename std::remove_pointer<
typename std::remove_cv<T>::type
>::type
>::type,
void
>::value
>
class has_deref_opr
{
template<
typename U,
typename R = decltype(has_deref_opr_sfinae_impl_helper(&U::operator->))
>
struct sfinae_impl { };
typedef char true_t;
struct false_t { true_t f[2]; };
template<typename U>
static true_t check(U*, sfinae_impl<U>* = 0);
template<typename U>
static false_t check(...);
public:
static bool const value = sizeof(check<T>(0)) == sizeof(true_t);
};
template<typename T>
class has_deref_opr<T, true>
{
public:
static bool const value = true;
};
:
has_deref_opr_sfinae_impl_helper
一些注意事项:
has_deref_opr
位于{{1}}内,不确定原因。也许这在更新版本的GCC中有所改变希望这有帮助。