我有一个具有多个构造函数的类,一个是可变参数,一个在可变参数之前接受一个额外的可调用函数。但是,我创建的对象会导致我不理解的重载解析。这是我的片段:
#include <iostream>
#include <functional>
struct Test
{
std::function<void()> func;
template<class... Args>
Test(Args&&... args)
{
std::cout << "Variadic" << std::endl;
}
template<class... Args>
Test(decltype(func) newfunc, Args&&... args)
{
std::cout << "Variadic with a callable" << std::endl;
}
};
int main()
{
auto l = [](){};
Test t{1,2,3}; //As expected
Test t2{l, 1,2,3}; //Not as expected
Test t3{{l}, 1,2,3}; //As expected, but why???
//Same test, just with temporary
Test t4{[](){}, 1,2,3};
Test t5{{[](){}}, 1,2,3};
return 0;
}
该程序(gcc 和 MSVC)的输出是
可变参数
可变参数
带有可调用的可变参数
可变参数
带有可调用的可变参数
第一个调用非常有意义,但我希望调用 2 会导致调用可调用,因为 std::function 对象可以从 lambda 创建。然而,事实并非如此,但是一旦我在情况 3 中将 lambda 包装在另一对大括号中,实质上将其转换为具有 1 个元素的初始化器_列表,就会调用正确的构造函数。我不明白的是为什么情况 2 不导致选择第二个重载以及为什么将其设为初始化列表会改变此行为。
lambda 不是
std::function
,它是 convertible_to 1。
当编译器看到以下形式的可变参数函数时
template<class... Args>
Test(Args&&... args)
...
template<class... Args>
Test(std::function<void()> newfunc, Args&&... args)
...
Test t4{[](){}, 1,2,3};
第一个非常适合,它不需要任何强制转换,第二个需要从 lambda 到
std::function
的强制转换,因此第一个是通过重载决策选择的。
在第三种情况下,括号
{l}
正在调用构造函数,然后将结果传递给函数,因此编译器必须在执行ADL之前弄清楚首先调用哪个构造函数,因此它决定调用std::function
构造函数,然后执行 ADL,这会导致第二个函数非常适合,因为它比函数 1 更专业并且不需要强制转换。
你可以通过应用一个概念来打破这个问题。
#include <iostream>
#include <functional>
#include <concepts>
template <typename T>
concept NotConvertibleTofunc = !std::convertible_to<T,std::function<void()>>;
struct Test
{
std::function<void()> func;
template<NotConvertibleTofunc Arg, class... Args>
Test(Arg&& arg, Args&&... args)
{
std::cout << "Variadic" << std::endl;
}
template<class... Args>
Test(decltype(func) newfunc, Args&&... args)
{
std::cout << "Variadic with a callable" << std::endl;
}
};
int main()
{
auto l = [](){};
Test t{1,2,3}; //As expected
Test t2{l, 1,2,3}; //Not as expected
Test t3{{l}, 1,2,3}; //As expected, but why???
//Same test, just with temporary
Test t4{[](){}, 1,2,3};
Test t5{{[](){}}, 1,2,3};
return 0;
}
Variadic
Variadic with a callable
Variadic with a callable
Variadic with a callable
Variadic with a callable