如何防止可变参数构造函数比副本构造函数更受青睐? [英] How can I prevent a variadic constructor from being preferred to the copy constructor?

查看:99
本文介绍了如何防止可变参数构造函数比副本构造函数更受青睐?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个模板'Foo',它拥有一个T,并且我希望它有一个可变参数的构造函数,将其参数转发给T的构造函数:

I have a template 'Foo', which owns a T, and I'd like it to have a variadic constructor that forwards its arguments to T's constructor:

template<typename T>
struct Foo {

    Foo()
        : t() {}

    Foo(const Foo& other)
        : t(other.t) {}

    template<typename ...Args>
    Foo(Args&&... args)
        : t(std::forward<Args>(args)...) {}

    T t;
};

但是,这导致Foo无法复制:

However, this causes Foo to not be copyable:

int main(int argc, char* argv[]) {
    Foo<std::shared_ptr<int>> x(new int(42));
    decltype(x) copy_of_x(x);  // FAILS TO COMPILE
    return EXIT_SUCCESS;
}

因为,根据这个答案,参数的非恒定性会使可变参数构造函数更好地匹配。出于明显的原因,我不想强​​迫我的调用者使用const_cast。

because, according to this answer, the non-constness of the argument causes the variadic constructor to be a better match. I don't want to force my callers to use const_cast, for obvious reasons.

我发现的一种可能的解决方案是为Foo写一个复制构造函数,它需要一个非常量Foo并使用构造函数转发:

One possible solution I found was to write a "copy constructor" for Foo which takes a non-const Foo and uses constructor forwarding:

Foo(Foo& other)
    : Foo(const_cast<const Foo&>(other)) {}

定义此构造函数后,事情又恢复了:现在非常量Foo参数副本ctor是首选。但是,这对我来说似乎很粗略,因为这种治愈似乎比疾病还糟。

When this constructor is defined, things work again: now the non-const Foo argument copy ctor is preferred. However, this seems very sketchy to me, in that this "cure" seems worse than the disease.

还有另一种方法可以达到这种效果,表明自然复制构造函数应该比可变参数构造函数更可取吗?如果不是,定义此非const参数副本构造函数会不会有不利后果?

Is there another way to achieve this effect, to indicate that the natural copy constructor should be preferred to the variadic constructor? If not, are there any adverse consequences of defining this non-const argument copy constructor?

推荐答案

您可以将一些丑陋的SFINAE与 std :: enable_if ,但我不确定它是否比您最初的解决方案要好(实际上,我很确定情况会更糟!):

You can use some ugly SFINAE with std::enable_if, but I'm not sure it is better than your initial solution (in fact, I'm pretty sure it's worse!):

#include <memory>
#include <type_traits>

// helper that was not included in C++11
template<bool B, typename T = void> using disable_if = std::enable_if<!B, T>;

template<typename T>
struct Foo {

    Foo() = default;
    Foo(const Foo &) = default;

    template<typename Arg, typename ...Args, typename = typename
        disable_if<
            sizeof...(Args) == 0 &&
            std::is_same<typename
                std::remove_reference<Arg>::type,
                Foo
            >::value
        >::type
    >
    Foo(Arg&& arg, Args&&... args)
        : t(std::forward<Arg>(arg), std::forward<Args>(args)...) {}

    T t;
};

int main(int argc, char* argv[]) {
    Foo<std::shared_ptr<int>> x(new int(42));
    decltype(x) copy_of_x(x);
    decltype(x) copy_of_temp(Foo<std::shared_ptr<int>>(new int));
    return 0;
}

这篇关于如何防止可变参数构造函数比副本构造函数更受青睐?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆