SFINAE重复构造函数声明

时间:2015-07-01 04:18:35

标签: c++ constructor sfinae

我想以一种方式为类创建构造函数,编译器在需要时可以轻松地创建它的新实例。

这是一个例子。

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以及我从另一个问题中学到的内容:Auto-constructor not working with <functional> objects

我设法找到一种方法来创建一个只匹配特定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&amp; f)三次,但是,我应该如何知道编译器为每种不同的情况使用不同的签名?

另一个答案暗示我要查看enable_if和is_convertible,但尚未设法为此问题设置解决方法。非常感谢任何帮助。

使用:Apple LLVM 6.0版(clang-600.0.57)(基于LLVM 3.5svn)

2 个答案:

答案 0 :(得分:1)

基于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([]() {});
}

答案 1 :(得分:1)

您当前的问题是您定义了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);