根据模板参数添加复制构造函数

ois*_*syn 7 c++ templates sfinae c++11

我有一个类似容器的类,如果底层类型是仅移动的,我只想移动,否则可以复制.为简单起见,我们假设可复制性由单个bool模板参数决定:

template<bool IsCopyable>
struct Foo
{
    Foo();
    Foo(const Foo&);    // only include this when IsCopyable is true
    Foo(Foo&&);

    Foo& operator=(const Foo&);  // only when IsCopyable
    Foo& operator=(Foo&&);
};
Run Code Online (Sandbox Code Playgroud)

现在,我不能只是SFINAE复制ctor,因为这需要使它模板化,模板化的功能不能复制ctor.另外,我不能只static_assert()在拷贝ctor中做一个.虽然这会捕获复制文件的错误用法,但它也使该类固有地从外部复制可构造(std::is_copy_constructible类型特征将产生真实).

顺便说一句,一个不幸的要求是它需要在VC++ 2012中编译,所以我不能使用花哨的表达式SFINAE,继承ctors,默认/删除函数或constexpr if(尽管如此,如果你有一个简洁的C++解决方案17我我还是想听听:))

显而易见的方法是使用模板专业化.我宁愿不走这条路,因为实际上Foo有很多功能,我不想重复自己.不过,这似乎是我唯一的选择,我可以使用基类实现一些代码共享,如下所示:

// Base functionality
template<bool IsCopyable>
struct FooBase
{
    FooBase();

    // move ctor and assignment can go here
    FooBase(FooBase&&);     
    FooBase& operator=(FooBase&&);

    // some generic conversion ctor and assignment that I happen to need
    template<class T> FooBase(T&& t);
    template<class T> FooBase& operator=(T&&);

    // ... all sorts of functionality and datamembers       
};

// Foo<false>
template<bool IsCopyable>
struct Foo : FooBase<IsCopyable>
{
    // can't use inheriting ctors in VS 2012, wrap the calls manually:
    Foo() { }
    Foo(Foo&& other) : FooBase<IsCopyable>(std::move(other)) { }
    Foo& operator=(Foo&& other)
    {
        FooBase<IsCopyable>::operator=(std::move(other));
        return *this;
    }

    template<class T> Foo(T&& t) : FooBase<IsCopyable>(std::forward<T>(t)) { }
    template<class T> Foo& operator=(T&& t)
    {
        FooBase<IsCopyable>::operator=(std::forward<T>(t));
        return *this;
    }
};

// Foo<true>
template<>
struct Foo<true> : FooBase<true>
{
    // add these
    Foo(const Foo&);
    Foo& operator=(const Foo&);

    // wrapping calls because of VS 2012:
    Foo() { }
    Foo(Foo&& other) : FooBase<true>(std::move(other)) { }
    Foo& operator=(Foo&& other)
    {
        FooBase<true>::operator=(std::move(other));
        return *this;
    }

    template<class T> Foo(T&& t) : FooBase<true>(std::forward<T>(t)) { }
    template<class T> Foo& operator=(T&& t)
    {
        FooBase<true>::operator=(std::forward<T>(t));
        return *this;
    }
};
Run Code Online (Sandbox Code Playgroud)

它仍然有点冗长.幸运的是,一旦你可以使用继承ctors和默认函数,它就会变得更清晰.尽管如此,我希望有一种更简单的方法,理想情况是不使用基类.

T.C*_*.C. 9

struct nonesuch {
private:
    ~nonesuch();
    nonesuch(const nonesuch&);
    void operator=(const nonesuch&);
};

template<bool IsCopyable>
struct Foo {
    Foo(const typename std::conditional<IsCopyable, Foo, nonesuch>::type& other) {
        // copy ctor impl here
    }
private:
    Foo(const typename std::conditional<!IsCopyable, Foo, nonesuch>::type&);
};
Run Code Online (Sandbox Code Playgroud)

同样适用于作业.