模板特化 - 编译器无法预测函数参数类型

问题描述 投票:0回答:1

我试图使用函数参数来专门化模板化函数,但编译器无法推断出正确的专门化。除非我明确说明函数类型,否则我会收到编译器错误。

#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 函数类型并选择正确的专业化。

c++ c++11
1个回答
0
投票

我希望/期望编译器能够正确推断 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; } }

工作演示

© www.soinside.com 2019 - 2024. All rights reserved.