gpt4 book ai didi

c++ - 使用 std::function 重载分辨率

转载 作者:IT老高 更新时间:2023-10-28 22:30:03 26 4
gpt4 key购买 nike

考虑这个代码示例:

#include <iostream>
#include <functional>

typedef std::function<void()> func1_t;
typedef std::function<void(int)> func2_t;

struct X
{
X (func1_t f)
{ }

X (func2_t f)
{ }
};

int main ( )
{
X x([](){ std::cout << "Hello, world!\n"; });
}

我确信它不应该编译,因为编译器不应该能够选择两个构造函数之一。 g++-4.7.3 显示了这种预期的行为:它说重载构造函数的调用是模棱两可的。不过g++-4.8.2编译成功了。

此代码在 C++11 中是否正确,还是此版本 g++ 的错误/功能?

最佳答案

在 C++11 中...

我们来看看std::function的构造函数模板的规范(接受任何 Callable):[func.wrap.func.con]/7-10

template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);

7 Requires: F shall be CopyConstructible. f shall be Callable (20.10.11.2) for argument types ArgTypes and return type R. The copy constructor and destructor of A shall not throw exceptions.

8 Postconditions: !*this if any of the following hold:

  • f is a NULL function pointer.
  • f is a NULL pointer to member.
  • F is an instance of the function class template, and !f

9 Otherwise, *this targets a copy of f initialized with std::move(f). [left out a note here]

10 Throws: shall not throw exceptions when f is a function pointer or a reference_wrapper<T> for some T. Otherwise, may throw bad_alloc or any exception thrown by F’s copy or move constructor.

现在,正在构造或尝试构造(用于重载决议)std::function<void(int)>来自 [](){} (即带有签名 void(void) )违反了 std::function<void(int)> 的要求的构造函数。

[res.on.required]/1

Violation of the preconditions specified in a function’s Requires: paragraph results in undefined behavior unless the function’s Throws: paragraph specifies throwing an exception when the precondition is violated.

所以,AFAIK,即使重载决议的结果也是未定义的。所以g++/libstdc++两个版本都在这方面符合。


在 C++14 中,这已被更改,参见 LWG 2132 .现在,std::function 的转换构造函数模板需要 SFINAE 拒绝不兼容的 Callables(下一章中有关 SFINAE 的更多信息):

template<class F> function(F f);
template <class F, class A> function(allocator_arg_t, const A& a, F f);

7 Requires: F shall be CopyConstructible.

8 Remarks: These constructors shall not participate in overload resolution unless f is Callable (20.9.11.2) for argument types ArgTypes... and return type R.

[...]

“不应参与重载决议”对应于通过 SFINAE 拒绝。最终效果是,如果您有一组重载的函数 foo ,

void foo(std::function<void(double)>);
void foo(std::function<void(char const*)>);

还有一个调用表达式,例如

foo([](std::string){}) // (C)

然后是 foo 的第二个重载被明确选择:自 std::function<F>定义 F作为它与外部的接口(interface),F定义哪些参数类型被传递到 std::function .然后,必须使用这些参数(参数类型)调用包装的函数对象。如果一个 double被传递到 std::function ,它不能被传递给一个采用 std::string 的函数, 因为没有转换 double -> std::string .对于 foo 的第一次重载, 论点 [](std::string){}因此不被视为可调用 std::function<void(double)> .构造函数模板已停用,因此无法从 [](std::string){} 进行转换至std::function<void(double)> .第一个重载从用于解决调用 (C) 的重载集中移除,只留下第二个重载。

请注意,由于 LWG 2420,上述措辞略有变化。 : 有一个异常(exception),如果返回类型 Rstd::function<R(ArgTypes...)>void , 然后任何返回类型都被上述构造函数模板中的 Callable 接受(并丢弃)。例如,[]() -> void {}[]() -> bool {}可调用 std::function<void()> .因此,以下情况会产生歧义:

void foo(std::function<void()>);
void foo(std::function<bool()>);

foo([]() -> bool {}); // ambiguous

重载解决规则不会尝试在不同的用户定义转换之间进行排名,因此 foo 的两个重载是可行的(首先),两者都不是更好。


SFINAE 如何在这方面提供帮助?

请注意,当 SFINAE 检查失败时,程序不是格式错误的,但该函数不适用于重载解决方案。例如:

#include <type_traits>
#include <iostream>

template<class T>
auto foo(T) -> typename std::enable_if< std::is_integral<T>::value >::type
{ std::cout << "foo 1\n"; }

template<class T>
auto foo(T) -> typename std::enable_if< not std::is_integral<T>::value >::type
{ std::cout << "foo 2\n"; }

int main()
{
foo(42);
foo(42.);
}

同样,通过在转换构造函数上使用 SFINAE 可以使转换不可行:

#include <type_traits>
#include <iostream>

struct foo
{
template<class T, class =
typename std::enable_if< std::is_integral<T>::value >::type >
foo(T)
{ std::cout << "foo(T)\n"; }
};

struct bar
{
template<class T, class =
typename std::enable_if< not std::is_integral<T>::value >::type >
bar(T)
{ std::cout << "bar(T)\n"; }
};

struct kitty
{
kitty(foo) {}
kitty(bar) {}
};

int main()
{
kitty cat(42);
kitty tac(42.);
}

关于c++ - 使用 std::function 重载分辨率,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22146749/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com