假设我正在编写一个类模板 C<T>
持有 T
值,所以 C<T>
仅当 T
时才可复制是可复制的。通常,当模板可能支持或不支持某个操作时,您只需定义该操作,由您的调用者决定是否在不安全时调用它:
template <typename T>
class C {
private:
T t;
public:
C(const C& rhs);
C(C&& rhs);
// other stuff
};
但是,这在复制构造函数的情况下会产生问题,因为 is_copy_constructible<C<T>>
即使在 T
时也是如此不可复制;特征看不到复制构造函数在被调用时格式错误。 这是一个问题,因为,例如,vector
如果 std::is_copy_constructible
有时会避免使用移动构造函数是真的。我该如何解决这个问题?
我相信is_copy_constructible
如果构造函数是显式或隐式默认的,将做正确的事情:
template <typename T>
class C {
private:
T t;
public:
C(const C& rhs) = default;
C(C&& rhs) = default;
// other stuff
};
但是,并不总是可以构造您的类以使默认构造函数做正确的事情。
我看到的另一种方法是使用 SFINAE 有条件地禁用复制构造函数:
template <typename T>
class C {
private:
T t;
public:
template <typename U = C>
C(typename std::enable_if<std::is_copy_constructible<T>::value,
const U&>::type rhs);
C(C&& rhs);
// other stuff
};
除了丑陋之外,这种方法的问题是我必须使构造函数成为模板,因为 SFINAE 仅适用于模板。根据定义,复制构造函数不是模板,所以我禁用/启用的实际上不是复制构造函数,因此它不会抑制编译器隐式提供的复制构造函数。
我可以通过显式删除复制构造函数来解决这个问题:
template <typename T>
class C {
private:
T t;
public:
template <typename U = C>
C(typename std::enable_if<std::is_copy_constructible<T>::value,
const U&>::type rhs);
C(const C&) = delete;
C(C&& rhs);
// other stuff
};
但这仍然不能阻止在重载决策期间考虑复制构造函数。这是一个问题,因为在其他条件相同的情况下,普通函数将在重载决策中击败函数模板,因此当您尝试复制 C<T>
时,普通的复制构造函数被选中,导致构建失败,即使 T
是可复制的。
我发现原则上可行的唯一方法是从主模板中省略复制构造函数,并在部分特化中提供它(在 T 不可复制时使用更多 SFINAE 技巧来禁用它)。然而,这很脆弱,因为它需要我复制 C
的整个定义。 ,这会造成两个拷贝不同步的主要风险。我可以通过让方法主体共享代码来缓解这种情况,但我仍然必须复制类定义和构造函数成员初始化列表,这为 bug 潜入提供了足够的空间。我可以通过让它们都继承来进一步缓解这种情况来自公共(public)基类,但引入继承可能会产生各种不受欢迎的后果。此外,当我试图做的只是禁用一个构造函数时,公共(public)继承似乎是不适合这项工作的工具。
有没有我没有考虑过的更好的选择?
最佳答案
一个值得注意的方法是周围类模板的部分特化。
template <typename T,
bool = std::is_copy_constructible<T>::value>
struct Foo
{
T t;
Foo() { /* ... */ }
Foo(Foo const& other) : t(other.t) { /* ... */ }
};
template <typename T>
struct Foo<T, false> : Foo<T, true>
{
using Foo<T, true>::Foo;
// Now delete the copy constructor for this specialization:
Foo(Foo const&) = delete;
// These definitions adapt to what is provided in Foo<T, true>:
Foo(Foo&&) = default;
Foo& operator=(Foo&&) = default;
Foo& operator=(Foo const&) = default;
};
这样 is_copy_constructible
特性就在 T
is_copy_constructible
的地方得到满足。
关于c++ - 有条件地禁用复制构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29929224/