c++ - 添加基于模板参数的拷贝构造函数

标签 c++ c++11 templates sfinae

我有一个类似容器的类,如果基础类型是只移动的,我希望它是只移动的,否则是可复制的。为简单起见,我们假设可复制性由单个 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&&);
};

现在,我不能只删除 SFINAE 复制构造函数,因为这需要将其模板化,而模板化函数不能作为复制构造函数。另外,我不能只在复制构造函数中执行 static_assert()。虽然这会捕获对复制构造函数的错误使用,但它也使类本身可从外部进行复制构造(std::is_copy_constructible 类型特征将产生 true)。

顺便说一下,一个不幸的要求是它需要在 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;
    }
};

还是有点啰嗦。幸运的是,一旦您可以使用继承构造函数和默认函数,它就会变得更清晰。不过,我希望有一种更简单的方法,最好是不使用基类。

最佳答案

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&);
};

同样适用于作业。

关于c++ - 添加基于模板参数的拷贝构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47342384/

相关文章:

C++ 业务规则表达式解析器/评估

python - Bottle.py 缓存模板,尽管处于 Debug模式

templates - Moodle 编辑模板

c++ - 使用 chrono 存储毫秒的可移植方式

c++ - 为什么空指针解引用不是异常

c++ - 将 unsigned long 除以 size_t 并将结果分配给 double

c++ - 初始化 std::string& 的私有(private)类变量

c++ - 在 C++ 中输出列表的 vector

c# - D2DERR_RECREATE_TARGET 错误是否真的意味着我必须跟踪渲染目标创建的所有内容?

c++ - 模板 : one works, 中的方法没有实例化