为什么这个函数指针的可变参数模板参数推导失败?
Why does the variadic template argument deduction fail for this function pointer?
在下面的最小示例中,S::foo
有效,但 S::bar
失败。
唯一的区别是参数包的顺序 Ts
和 Us
。
struct FPtr
和 S::lol
是我找到的最好的解决方法,但在实践中使用起来相当不舒服。
为什么 bar
的参数推导会失败(特别是因为我已经明确指定了类型,所以根本不应该发生推导)?这是一个编译器错误(出现在 clang++ 3.5
和 g++ 4.9
中),还是出于某种原因这是标准中的错误?
template<typename ... Ts>
struct FPtr {
FPtr(void (*val)(Ts ...)) : val{val} {}
void (*val)(Ts ...);
};
template<typename ... Ts>
struct S {
template<typename ... Us>
void lol(FPtr<Us ..., Ts ...>) {}
template<typename ... Us>
void foo(void (*)(Ts ..., Us ...)) {}
template<typename ... Us>
void bar(void (*)(Us ..., Ts ...)) {}
};
void f(int, float) {}
void g(float, int) {}
int main() {
S<int> s;
s.lol<float>(FPtr<float, int>(g));
s.foo<float>(f);
s.bar<float>(g);
}
错误信息是:
$ clang++ -std=c++14 t27.cpp -Wall -Wextra -pedantic
t27.cpp:31:4: error: no matching member function for call to 'bar'
s.bar<float>(g);
~~^~~~~~~~~~
t27.cpp:18:7: note: candidate template ignored: failed template argument deduction
void bar(void (*)(Us ..., Ts ...)) {}
^
我已经用 Clang 和 GCC 测试了这段代码,它们都无法编译程序。我会说这是两个编译器中的错误。出现在参数列表末尾之前的函数参数包是非推导上下文。在替换明确指定的模板参数后,它应该构建函数
template<>
S<int>::bar(void (*)(float, int));
这应该与呼叫相匹配。 Clang 和 GCC 以前在这样的领域遇到过问题,并且众所周知,他们的诊断没有多大帮助。然而令人惊讶的是 VC++ 编译了代码。
考虑以下在两种编译器下都有效的内容。
template<class... Ts>
struct S {
template<class... Us>
void bar(Us..., Ts...);
};
int main() {
S<int>().bar<int>(1, 2);
}
你们的程序语义相同,应该一视同仁。
在下面的最小示例中,S::foo
有效,但 S::bar
失败。
唯一的区别是参数包的顺序 Ts
和 Us
。
struct FPtr
和 S::lol
是我找到的最好的解决方法,但在实践中使用起来相当不舒服。
为什么 bar
的参数推导会失败(特别是因为我已经明确指定了类型,所以根本不应该发生推导)?这是一个编译器错误(出现在 clang++ 3.5
和 g++ 4.9
中),还是出于某种原因这是标准中的错误?
template<typename ... Ts>
struct FPtr {
FPtr(void (*val)(Ts ...)) : val{val} {}
void (*val)(Ts ...);
};
template<typename ... Ts>
struct S {
template<typename ... Us>
void lol(FPtr<Us ..., Ts ...>) {}
template<typename ... Us>
void foo(void (*)(Ts ..., Us ...)) {}
template<typename ... Us>
void bar(void (*)(Us ..., Ts ...)) {}
};
void f(int, float) {}
void g(float, int) {}
int main() {
S<int> s;
s.lol<float>(FPtr<float, int>(g));
s.foo<float>(f);
s.bar<float>(g);
}
错误信息是:
$ clang++ -std=c++14 t27.cpp -Wall -Wextra -pedantic
t27.cpp:31:4: error: no matching member function for call to 'bar'
s.bar<float>(g);
~~^~~~~~~~~~
t27.cpp:18:7: note: candidate template ignored: failed template argument deduction
void bar(void (*)(Us ..., Ts ...)) {}
^
我已经用 Clang 和 GCC 测试了这段代码,它们都无法编译程序。我会说这是两个编译器中的错误。出现在参数列表末尾之前的函数参数包是非推导上下文。在替换明确指定的模板参数后,它应该构建函数
template<>
S<int>::bar(void (*)(float, int));
这应该与呼叫相匹配。 Clang 和 GCC 以前在这样的领域遇到过问题,并且众所周知,他们的诊断没有多大帮助。然而令人惊讶的是 VC++ 编译了代码。
考虑以下在两种编译器下都有效的内容。
template<class... Ts>
struct S {
template<class... Us>
void bar(Us..., Ts...);
};
int main() {
S<int>().bar<int>(1, 2);
}
你们的程序语义相同,应该一视同仁。