ple*_*ndo 2 c++ templates type-traits language-lawyer c++17
我在以下程序中遇到 std::is_invocable 问题:
#include <iostream>
#include <type_traits>
void g() {}
template<bool B, typename T>
void f(T t) {
if constexpr (B)
g(t);
}
int main() {
std::cerr << std::boolalpha <<
std::is_invocable_v<decltype(&f<true, int>), int> << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
我原以为程序输出为假,因为 f<true, int> 无法实例化。但是,GCC(从 10.0.1 20200224 开始)不会编译,错误消息为
test.cpp: In instantiation of 'void f(T) [with bool B = true; T = int]':
test.cpp:14:51: required from here
test.cpp:9:10: error: too many arguments to function 'void g()'
9 | g(t);
| ~^~~
test.cpp:4:6: note: declared here
4 | void g() {}
|
Run Code Online (Sandbox Code Playgroud)
和 Clang(从 11.0.0 开始)甚至打印true。
在这种情况下,正确的行为是什么?
Bar*_*rry 10
问题归结为:decltype(&f<true, int>)
实际上实例化了f<true, int>
吗?
如果是,则是病态的程序,因为生病,形成实例(不能调用g
用int
,如要求)。
如果不是,那么正确答案invocable_v
是true
- 因为函数体上没有 SFINAE,并且函数的签名明确允许此调用。
似乎 gcc 认为是(和硬错误),而 clang 认为不是(并产生了true
)。我认为clang在这里是正确的。我们的规则是:
如果以涉及重载解析的方式使用函数模板或成员函数模板特化,则隐式实例化特化声明 ([temp.over])。
实现不应隐式实例化函数模板、变量模板、成员模板、非虚拟成员函数、成员类、类模板的静态数据成员或 constexpr if 语句的子语句 ([stmt. if]),除非需要这样的实例化。
我们在这里确实涉及重载解析(函数地址),但这只是实例化函数模板的声明。我认为不需要实例化函数模板的定义(f
返回void
,而不是类似的东西auto
),所以 gcc 在这里太急切地实例化它。
也就是说,它当然不应该 yield false
。
归档时间: |
|
查看次数: |
176 次 |
最近记录: |