W.F*_*.F. 18 c++ language-lawyer c++11 trailing-return-type
考虑最小的例子:
template <int>
struct bar { };
int main() 
{
    [](auto i) -> bar<i> { return {}; };
}
甚至:
template <int>
struct bar {};
template <class I>
auto foo(I i) -> bar<i> {}
clang编译两种形式没有问题,但gcc发现使用无效(例如1),(例如2)
这个问题可能看起来很愚蠢,但是参数的类型可以让constexpr转换运算符重载(在这种情况下,i从传递给lambda/foo的值推导出的类型int是以constexpr方式推导出来的),在这种情况下,不要强迫它做一些变通方法直接访问它...
这似乎是一个gcc错误.我把它报告为问题#80242.
gcc抱怨i作为模板参数的有效性:
错误:模板参数1无效
我已经按照C++语法从trailing-return-type到template-argument,这需要一个constant-expression:
模板参数:
- 常量表达式 < -
- 类型ID
- ID-表达
真正的问题就变成:"是i有效的constant-expression吗?" .
我认为答案是肯定的,因为§8.20.4 [expr.const]说:
甲转换常量表达式类型
T是一个表达式,隐式转换为类型T,其中,所述转换后的表达式是一个常量表达式和隐式转换序列只包含:
- 用户定义的转换,
[...]
(注意:这些表达式可以在新表达式中使用,作为case表达式,如果基础类型是固定的,则作为枚举器初始化器,作为数组边界,以及作为非类型模板参数.)
有一系列隐式转换,从开始i,将产生一个转换的常量表达式,它是一个常量表达式.鉴于:
template <int>
struct bar { };
template <class I>
auto foo(I i) -> bar<i> { }
int main()
{
    foo(std::integral_constant<int, 1>{}); // (0)
}
在(0)函数调用的上下文中,参数i是一个实例std::integral_constant<int, 1>.
std::integral_constant提供constexpr用户定义的底层转换value_type.
转换的常量表达式明确允许用户定义的转换,如上面§8.20.4 [expr.const]所示.
std::integral_constant::operator value_type()将返回非类型模板参数1.这是一个核心常量表达式,因为它不违反§8.20.2  [expr.const]中指定的任何规则.
因此,转换的常量表达式是常量表达式.
我相信你的两个例子都是错的.基于标准措辞5.20常量表达式[expr.const] /p2.7:
2条件表达式e是核心常量表达式,除非按照抽象机器(1.9)的规则评估e将评估以下表达式之一:j
...
- 左值 - 右值转换(4.1),除非它适用于:
函数参数不能是常量表达式,因为为了将它们作为模板参数传递,您将lvalue应用于它们的右值转换.
在CLANG和GCC中,如果你实例化模板,你将会根据上面的措辞得到一个错误.我相信,因为在示例中没有模板被实例化,所以不需要诊断,因此两个编译器都是正确的.