在enable_if'd成员函数上调用bind时会出错。我已经使用if constexpr
解决了这个问题,但我很好奇这个问题的解决方案是什么。代码是最简单的再现器,并不代表我试图解决的首要问题。我该怎么做呢?
#include <iostream>
#include <type_traits>
#include <functional>
template <typename T>
class test {
public:
template <typename U = T>
typename std::enable_if<std::is_copy_constructible<U>::value, void>::type
foo(const T& v){
std::cout << "copy constructible";
}
template <typename U = T>
typename std::enable_if<!std::is_copy_constructible<U>::value, void>::type
foo(const T& v){
std::cout << "not copy constructible";
}
void foo_bar(const T& v){
std::cout << "test";
}
};
int main(int argn, char** argc){
test<int> myfoo;
myfoo.foo(3); //Works
auto func = std::bind(&test<int>::foo_bar, &myfoo, 3); //Works
auto func = std::bind(&test<int>::foo, &myfoo, 3); //Doesn't work
func();
return 0;
}
问题是U
只在实际调用成员函数模板foo
时被替换,而不是在std::bind()
内部使用时。这意味着当在bind()
中指定&test<int>::foo
时,不知道两个成员函数模板中的哪一个将实际实例化,因为定义的实例化将在我们实际调用foo()
时发生,因此编译器无法确定您引用的是哪一个。这正是<unresolved overloaded function type>
在你得到的错误中的意思:
no matching function for call to 'bind(<unresolved overloaded function type>, test<int>*, int)'
32 | auto func2 = std::bind(&test<int>::foo, &myfoo, 3); //Doesn't work
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~
您可以通过显式指定U
来解决这个问题,如:
&test<int>::foo<int>
或使用lambda,如:
auto func = [&myfoo]() { myfoo.foo(3); };
在c++ 20中有第三种方法可以使用requires-clause
解决这个问题,如下所示。注意,下面的程序是格式良好的,但是gcc和msvc错误地拒绝了它。只有clang接受它,这是正确的行为。演示
#include <iostream>
#include <type_traits>
#include <functional>
template <typename T>
class test {
public:
void foo(const T& v) requires std::is_copy_constructible_v<T>{
std::cout << "copy constructible";
}
void foo(const T& v) requires (!std::is_copy_constructible_v<T>) {
std::cout << "non copy constructible";
}
void foo_bar(const T& v){
std::cout << "test";
}
};
int main(int argn, char** argc){
test<int> myfoo;
myfoo.foo(3); //Works
auto func = std::bind(&test<int>::foo_bar, &myfoo, 3); //Works
auto func2 = std::bind(&test<int>::foo, &myfoo, 3); //works
func();
func2();
}