为什么返回类型中的decltype表达式必须在符号名称中被改变?

我最近发现decltype表达式被当作函数符号名称的一部分,当用作返回类型时,它会成为令人讨厌的分段错误的原因,同时对表达式进行解构(例如在调试会话中),如果表达式是太复杂了。

第一个版本在函数返回类型中使用decltype,其中完整表达式被破坏(http://goo.gl/EALubx):

#include <cstdint>
#include <utility>

struct A { void bar() const; };

template<typename T>
decltype(std::declval<T>().bar()) foo(T const& a);

void foo() { A a; return foo(a); }

被编译为(GCC 5.2.0):

foo():
        sub     rsp, 24
        lea     rdi, [rsp+15]
        call    decltype ((((declval<A>)()).bar)()) foo<A>(A const&)
        add     rsp, 24
        ret

第二个版本几乎等同于表达式类型被解析为附加模板参数(http://goo.gl/DfQGR5)的一部分:

#include <cstdint>
#include <utility>

struct A { void bar() const; };

template<typename T, typename R=decltype(std::declval<T>().bar())>
R foo(T const& a);

void foo() { A a; return foo(a); }

被编译为(GCC 5.2.0):

foo():
        sub     rsp, 24
        lea     rdi, [rsp+15]
        call    void foo<A, void>(A const&)
        add     rsp, 24
        ret

我知道模板函数只能在它们的返回类型上重载,但是编译器不应该自己解决decltype表达式,而是改变结果类型呢?

任何人都可以告诉我为什么,或者指出我在C ++规范中指定的位置?


回答:

正如评论中TC所解释的,原因在于模板函数过载规则[temp.over.link]/5-6

例如:

// #1
template<typename T>
decltype(std::declval<T>().bar()) foo(T const& a);

// #2 same function as #1, because both are "equivalent":
// declared in the same scope, with the same name and 
// argument/return type expressions are "equivalent"
template<typename U>
decltype(std::declval<U>().bar()) foo(U const& a);

// #3 overloads #1, because argument/return type expressions
// may not be resolved to the same value for any given set of T
template<typename T>
decltype(std::declval<T>().baz()) foo(T const& a);

这也意味着以下是不合格的:

// #1
template<typename T>
decltype(std::declval<T>().bar(2)) foo(T const& a);

// #2 is "functionally equivalent" but not "equivalent" to #1
// because argument/return type expressions are not "equivalent"
// but "functionally equivalent": they are resolved to the same value
// for any given T
template<typename T>
decltype(std::declval<T>().bar(1+1)) foo(T const& a);
链接地址: http://www.djcxy.com/p/66507.html

上一篇: Why decltype expressions in return types have to be mangled in the symbol name?

下一篇: Capture function argument type from actual arguments