根据[5/8]和[7.1.7.2/4](工作草案):
decltype
说明符的操作数是未评估的操作数 请考虑以下代码:
#include<type_traits>
struct S { using type = int; };
int f(int i);
template<typename T>
typename T::type g(T);
template<typename T>
auto h(T v) { return v; }
int main() {
static_assert(std::is_same<decltype(f(42)), int>::value, "!");
static_assert(std::is_same<decltype(g(S{})), int>::value, "!");
static_assert(std::is_same<decltype(h(42)), int>::value, "!");
}
不言而喻,实际上并未对f
和g
进行评估
另一方面,函数h
具有auto
返回类型,该类型是从其主体推断出来的,因此来自其参数,因此来自推导出的类型T
。
在这种情况下,它仍然可以被视为未评估的操作数吗?
我的意思是,在我看来,在decltype
的上下文中,函数h
必须进行评估才能知道实际的返回类型是什么。
因为我很确定工作草案是对的,问题是:我的推理出了什么问题?
答案 0 :(得分:11)
为了确定decltype(h(42))
表示的类型,编译器需要对h
执行模板参数推导,并实例化模板特化h<int>
以检查其主体并确定返回类型。这不与评估h(42)
相同;例如,如果h
包含任何副作用,例如打印消息,则不会发生这些副作用。
答案 1 :(得分:1)
在这种情况下,它仍然可以被视为未评估的操作数吗?一世 意思是,在我看来,在decltype的背景下, 必须评估函数h以了解实际的返回类型。
它仍然是一个未评估的背景。正如Brain's answer(这是较短的答案)所解释的那样。
C ++标准讨论模板参数推导过程,并用参数替换函数模板: [temp.deduct/7] (强调我的):
替换发生在所有使用的类型和表达式中 函数类型和模板参数声明。该 表达式不仅包括常量表达式,例如那些 出现在数组边界或非类型模板参数中
sizeof
内的一般表达式(即非常量表达式),decltype
以及允许非常量表达式的其他上下文。 替换以词汇顺序进行,并在条件出现时停止 导致扣除失败的原因。
您可以从the first paragraph开始阅读,以获取有关模板参数扣除的更多详细信息。
(注:所有引用的段落都部分转载,点击章节链接查看完整段落):
由于您已经了解了decltype
和未评估的上下文,并且引用了相关部分,因此我们可以跳过这些部分并从auto
开始......
[dcl.spec.auto/1]:
auto
和decltype(auto)
类型说明符用于指定 占位符类型,稍后将通过从中扣除来替换 初始化....
来自 占位符类型的视图 :
[dcl.spec.auto/2]:占位符类型可以带有函数声明符... ... 如果函数的声明返回类型包含占位符 type ,函数的返回类型是从非丢弃中推导出来的 函数体中的
return
语句(如果有的话)
关于占位符类型扣除:
<强> [dcl.type.auto.deduct/1] 强> 占位符类型扣除是包含a的类型的过程 占位符类型由推断类型替换。
扣除占位符返回类型:
<强> [type.auto.deduct/4] 强> 如果占位符是自动类型说明符,则推导出类型
T'
使用模板参数的规则确定替换T
扣强>
如果故事不是很清楚,您可能需要阅读每个引用段落的整个部分。