[英]decltype(auto) in member function ignores invalid body, decltype(expr) fails
我有一个简单的模板化包装器结构,其成员函数在其模板类型的对象上调用.error()
。
template <typename T>
struct Wrapper {
T t;
decltype(auto) f() {
return t.error(); // calls .error()
}
};
如果我使用没有error()
成员函数的类型实例化它,只要我不调用它就没问题。 这是我想要的行为。
Wrapper<int> w; // no problem here
// w.error(); // uncommented causes compilation failure
如果我使用我认为是跟踪返回类型的语义等价物,它就会在变量声明中出错
template <typename T>
struct Wrapper {
T t;
auto f() -> decltype(t.error()) {
return t.error();
}
};
Wrapper<int> w; // error here
我会接受两者在语义上没有等价,但是无论如何使用尾随返回类型(仅限C ++ 11)来获取前者的行为而不使用某种HasError
tmp HasError
专门化整个类?
版本之间的差异
decltype(auto) f();
auto f() -> decltype(t.error());
是第二个函数声明可能无效。 函数模板的返回类型推导在定义实例化时发生[dcl.spec.auto] / 12 。 虽然我找不到关于类模板的成员函数的返回类型推导的任何内容,但我认为它们的行为类似。
隐式地实例化类模板Wrapper
导致声明的实例,但不是所有的(非虚拟)成员函数[temp.inst] / 1的定义 。 声明decltype(auto) f();
有一个未推断的占位符但有效。 另一方面, auto f() -> decltype(t.error());
某些实例化的返回类型无效。
C ++ 11中的一个简单解决方案是推迟返回类型的确定,例如将f
转换为函数模板:
template<typename U = T>
auto f() -> decltype( std::declval<U&>().error() );
尽管如此,该功能的定义让我有点担心:
template<typename U = T>
auto f() -> decltype( std::declval<U&>().error() )
{
return t.error();
}
对于Wrapper
的特殊化,其中t.error()
无效,上面的f
是一个无法生成有效特化的函数模板。 这可能属于[temp.res] / 8,这表示此类模板格式错误,无需诊断:
如果无法为模板生成有效的专门化,并且未实例化该模板,则模板格式错误,无需诊断。
但是,我怀疑已引入规则允许但不要求实现检查非实例化模板中的错误。 在这种情况下, 源代码中没有编程错误; 在源代码描述的类模板的实例化中会发生错误。 因此,我认为应该没问题。
另一种解决方案是使用回退返回类型来使函数声明格式良好,即使定义不是(对于所有实例化):
#include <type_traits>
template<typename T> struct type_is { using type = T; };
template <typename T>
struct Wrapper {
T t;
template<typename U=T, typename=void>
struct error_return_type_or_void : type_is<void> {};
template<typename U>
struct error_return_type_or_void
<U, decltype(std::declval<U&>().error(), void())>
: type_is<decltype(std::declval<U&>().error())> {};
auto f() -> typename error_return_type_or_void<>::type {
return t.error();
}
};
一种方法是标记的crtp。
// todo:
template<class T>
struct has_error; // true_type if T.error() is valid
template<class D,class T,bool Test=has_error<T>{}>
struct do_whatever {
D* self(){return static_cast<D*>(this);}
D const* self()const{return static_cast<D const*>(this);}
auto f()->decltype(self()->t.error()) {
return self()->t.error();
}
};
template<class D,class T>
struct do_whatever<D,T,false>{};
如果T
没有error()
,那么f()
就不存在了。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.