【发布时间】:2017-11-09 05:04:59
【问题描述】:
参考以下代码
#include <iostream>
#include <tuple>
#include <string>
#include <type_traits>
using std::cout;
using std::endl;
using std::string;
template <typename... Args>
void bar(Args&&...) {}
int change(const string&) { return 1; }
double change(int) { return 1.0; }
int main() {
// bar(1, 2.0, static_cast<int(*)(const string&)>(&change));
bar(1, 2.0, &change);
return 0;
}
我知道上面代码中的错误是对change函数的引用不明确(这就是注释行起作用的原因),但是为什么编译器会给出这个错误信息呢?
test.cpp:17:5: error: no matching function for call to 'bar'
bar(1, 2.0, &change);
^~~
test.cpp:11:6: note: candidate function not viable: requires 2 arguments, but 3 were
provided
void bar(Args&&...) {}
^
1 error generated.
这发生在 gcc (>5) 和 clang (Apple LLVM version 8.0.0 (clang-800.0.42.1)) 上
我只是好奇为什么两个编译器不只是说引用不明确。我觉得这与模板实例化在 C++ 中的工作方式有关,但我不确定确切的原因。
【问题讨论】:
-
我会说这是一个编译器错误
-
有趣的是,在 VS2017 Intellisense 上会给出“正确”的错误消息,而编译器本身会给出与在 GCC 和 Clang 上观察到的相同的错误
-
@Justin 即使它是一个编译器错误,显然同样的错误出现在多个独立的编译器中。这意味着幕后可能会发生更有趣的事情。
-
有可能,因为
&change格式不正确,编译器将其视为“不是一个值”并做一些奇怪的事情。这可能会导致他们将模板实例化为bar<int, double>,因为“非值”不是类型,因此它没有插入到模板参数列表中,这意味着函数被调用时使用了太多参数。在 GCC 的情况下,看起来“不是值”使整个类型列表为空 (with Args = {}) -
按照标准,当你输入一个格式错误的程序时,编译器可以给出任何诊断(甚至是空格!)。所以它们是符合标准的:但是,符合标准的错误消息有点太低了。 ;)
标签: c++ c++11 templates gcc clang