SFINAE 重复构造函数声明
SFINAE Duplicate constructor declaration
我想为 class 创建构造函数,以便编译器在需要时简单地创建它的新实例。
这是一个例子。
class C {
public:
C(int) {}; // int constructor
};
如果我再声明一个函数:
void F(C _c) {};
我可以用一个 int 调用这个,并让编译器处理 C 的构造:
F(0); // works
我想做的是实现同样的事情,但是使用lambdas作为参数,举几个例子:
F([]() {}); //A
F([](int) {}); //B
F([](int)->int { return 0; }); //C
使用 SFINAE 以及我从另一个问题中学到的知识:
我设法找到了一种方法来创建仅匹配特定 lambda 签名的构造函数,结果如下:
template<typename F, typename = decltype(function<void(void)>(declval<F&>()))> C(F&& f) {}; //For lambda's like A
template<typename F, typename = decltype(function<void(int)>(declval<F&>()))> C(F&& f) {}; //For lamdba's like B
template<typename F, typename = decltype(function<int(int)>(declval<F&>()))> C(F&& f) {}; //For lambda's like C
现在我遇到的问题是,如果我一次添加这三个定义,我会收到一条错误消息,指出我正在尝试重新定义 C 的构造函数。这是正确的,因为,是的,正在定义构造函数作为 C(F&& f) 三次,但是,我应该如何让编译器知道为每个不同的情况使用不同的签名?
另一个答案提示我查看 enable_if 和 is_convertible,但未能针对此问题设置解决方法。非常感谢任何帮助。
使用:Apple LLVM 版本 6.0 (clang-600.0.57)(基于 LLVM 3.5svn)
基于top answer here,这就是我想出的。它可能有点粗糙,可以改进,但它的主要功能(在在线 clang 3.5.0 上试过)。
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
typedef ReturnType(signature)(Args... args);
typedef ReturnType(*ptr_signature)(Args... args);
};
class C
{
public:
template<typename F> C(F&& f) {
typedef function_traits<F> traits;
I<F>(std::move(f), reinterpret_cast<typename traits::ptr_signature>(0));
}
template<typename F> void I(F&& f, void(*)()) { std::cout << "Hello void(void) lambda" << std::endl; };
template<typename F> void I(F&& f, void(*)(int)) { std::cout << "Hello void(int) lambda" << std::endl; };
template<typename F> void I(F&& f, int(*)(int)) { std::cout << "Hello int(int) lambda" << std::endl; };
};
int main()
{
C([](int i) { return i;});
C([](int i) {});
C([]() {});
}
你现在的问题是你定义了3次
template <typename F, typename> C(F&&);
但使用不同的默认参数(执行 SFINAE)。
您可以更改为
// Use to have different type easily
template <std::size_t> struct dummy {}
template<typename F, decltype(function<void(void)>(declval<F&>()), dummy<0>())* = nullptr> C(F&& f);
template<typename F, decltype(function<void(int)>(declval<F&>()), dummy<1>())* = nullptr> C(F&& f);
template<typename F, decltype(function<int(int)>(declval<F&>()), dummy<2>())* = nullptr> C(F&& f);
所以你有 3 个不同的签名:
template<typename F, dummy<0>*> C(F&& f);
template<typename F, dummy<1>*> C(F&& f);
template<typename F, dummy<2>*> C(F&& f);
我想为 class 创建构造函数,以便编译器在需要时简单地创建它的新实例。
这是一个例子。
class C {
public:
C(int) {}; // int constructor
};
如果我再声明一个函数:
void F(C _c) {};
我可以用一个 int 调用这个,并让编译器处理 C 的构造:
F(0); // works
我想做的是实现同样的事情,但是使用lambdas作为参数,举几个例子:
F([]() {}); //A
F([](int) {}); //B
F([](int)->int { return 0; }); //C
使用 SFINAE 以及我从另一个问题中学到的知识:
我设法找到了一种方法来创建仅匹配特定 lambda 签名的构造函数,结果如下:
template<typename F, typename = decltype(function<void(void)>(declval<F&>()))> C(F&& f) {}; //For lambda's like A
template<typename F, typename = decltype(function<void(int)>(declval<F&>()))> C(F&& f) {}; //For lamdba's like B
template<typename F, typename = decltype(function<int(int)>(declval<F&>()))> C(F&& f) {}; //For lambda's like C
现在我遇到的问题是,如果我一次添加这三个定义,我会收到一条错误消息,指出我正在尝试重新定义 C 的构造函数。这是正确的,因为,是的,正在定义构造函数作为 C(F&& f) 三次,但是,我应该如何让编译器知道为每个不同的情况使用不同的签名?
另一个答案提示我查看 enable_if 和 is_convertible,但未能针对此问题设置解决方法。非常感谢任何帮助。
使用:Apple LLVM 版本 6.0 (clang-600.0.57)(基于 LLVM 3.5svn)
基于top answer here,这就是我想出的。它可能有点粗糙,可以改进,但它的主要功能(在在线 clang 3.5.0 上试过)。
template <typename T>
struct function_traits
: public function_traits<decltype(&T::operator())>
{};
template <typename ClassType, typename ReturnType, typename... Args>
struct function_traits<ReturnType(ClassType::*)(Args...) const>
{
typedef ReturnType(signature)(Args... args);
typedef ReturnType(*ptr_signature)(Args... args);
};
class C
{
public:
template<typename F> C(F&& f) {
typedef function_traits<F> traits;
I<F>(std::move(f), reinterpret_cast<typename traits::ptr_signature>(0));
}
template<typename F> void I(F&& f, void(*)()) { std::cout << "Hello void(void) lambda" << std::endl; };
template<typename F> void I(F&& f, void(*)(int)) { std::cout << "Hello void(int) lambda" << std::endl; };
template<typename F> void I(F&& f, int(*)(int)) { std::cout << "Hello int(int) lambda" << std::endl; };
};
int main()
{
C([](int i) { return i;});
C([](int i) {});
C([]() {});
}
你现在的问题是你定义了3次
template <typename F, typename> C(F&&);
但使用不同的默认参数(执行 SFINAE)。
您可以更改为
// Use to have different type easily
template <std::size_t> struct dummy {}
template<typename F, decltype(function<void(void)>(declval<F&>()), dummy<0>())* = nullptr> C(F&& f);
template<typename F, decltype(function<void(int)>(declval<F&>()), dummy<1>())* = nullptr> C(F&& f);
template<typename F, decltype(function<int(int)>(declval<F&>()), dummy<2>())* = nullptr> C(F&& f);
所以你有 3 个不同的签名:
template<typename F, dummy<0>*> C(F&& f);
template<typename F, dummy<1>*> C(F&& f);
template<typename F, dummy<2>*> C(F&& f);