c++ - 成员函数中的 decltype(auto) 忽略无效主体,decltype(expr) 失败

标签 c++ templates c++11 c++14

我有一个简单的模板化包装器结构,其成员函数在其模板类型的对象上调用 .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 欺骗?

最佳答案

版本之间的区别

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,它表示此类模板格式错误,无需诊断:

If no valid specialization can be generated for a template, and that template is not instantiated, the template is ill-formed, no diagnostic required.

但是,我怀疑该规则已引入允许,但不要求实现检查非实例化模板中的错误。在这种情况下,源代码中没有编程错误;该错误将发生在源代码描述的类模板的实例化中。所以,我觉得应该没问题。


另一种解决方案是使用后备返回类型使函数声明格式正确,即使定义不是(对于所有实例化):

#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();
    }
};

关于c++ - 成员函数中的 decltype(auto) 忽略无效主体,decltype(expr) 失败,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29463711/

相关文章:

c++ - 为特定类覆盖 new 和 delete 运算符的原因是什么?

c++ - 支持多线程应用程序回调的 linux 共享库

c++ - Opengl 4 调试输出不起作用

c++ - 基于模板参数的不同类实现

c++ - 根据类成员对同一键的多映射元素进行排序?

c++ - 为什么 std::uncaught_exception 会变成 std​​::uncaught_exceptions?

c++ - 包含自身实例化的模板,C++ 中的递归

c++ - 隐藏在类默认模板参数后面的方法中的默认模板参数

c++ - C++ 模板中的模板参数

c++ - 使用 std::is_same、std::result_of 和 std::bind 时,static_assert 无法按预期工作