我试图使用函数参数来专门化模板化函数,但编译器无法推断出正确的专门化。除非我明确说明函数类型,否则我会收到编译器错误。
#include <functional>
int data;
using MyFunction = std::function<int()>;
template<class T> void set(const T& value)
{
data = value;
}
template<> void set<MyFunction>(const MyFunction& f)
{
data = f();
}
int main()
{
set(1); // OK
MyFunction f2 = []() { return 1; }; // OK
set(f2);
auto f1 = []() { return 1; }; // COMPILE ERROR
set(f1);
set([]() { return 1; }); // COMPILE ERROR
return 0;
}
编译器错误(g++/c++11):
main.cpp: In instantiation of ‘void set(const T&) [with T = main()::<lambda()>]’:
main.cpp:26:8: required from here
main.cpp:10:10: error: invalid user-defined conversion from ‘const main()::’ to ‘int’ [-fpermissive]
10 | data = value;
| ~~~~~^~~~~~~
main.cpp:25:15: note: candidate is: ‘constexpr main()::::operator int (*)()() const’ (near match)
25 | auto f1 = []() { return 1; }; // COMPILE ERROR
示例代码包含我尝试的精简版本。尝试了 C++11、14、17、20,结果相同。 MSVC 16 和 g++,结果相似。
我希望/期望编译器能够正确推断 lambda 函数类型并选择正确的专业化。
我希望/期望编译器能够正确推断 lambda 函数类型并选择正确的专业化。
问题是在模板参数推导过程中不考虑隐式转换。
要解决这个问题,要么只提供普通的非模板重载而不是专门化,或者替代方法是使用std::is_invocable_r
constexpr if
,如下所示:
template <class T> void set(T const& value)
{
if constexpr (std::is_invocable_r_v<int, T>)
{
data = value();
}
else
{
data = value;
}
}