确保派生 class 在保持默认移动/移动分配的同时实现静态方法
Ensure derived class implements static method while maintaining default move / move assign
我想确保一些派生的 classes 实现了一个静态方法并发现了这个 SO 问题:Ensure derived class implements static method 最佳答案使用 CRTP 来解决 static_assert
的问题在基础 class 析构函数中确保模板参数类型实现 static int foo(int)
.
但是,正如对答案的评论所指出的“这个答案有一个小问题:写出析构函数会导致禁用移动构造函数和移动赋值运算符的生成。它还阻止了对象从 trivially_destructible。所以,虽然它有效,但这种方法有缺点(这些缺点适用于其他特殊成员)。” – @Matthieu M
有没有办法避免这种不利影响?我试过将 static_assert
移动到 Base
的成员函数和静态成员函数,但在这两种情况下,当派生的 class 不产生编译时错误'实施 static int foo()
。这是我一直在使用的代码(根据上面的 SO 线程调整):
#include <type_traits>
template <class T>
class Base {
public:
//~Base() //This works as expected! Compile error because Bad doesn't implement static int foo()
//{
// static_assert(std::is_same<decltype(T::foo()), int>::value, "ERROR: No 'static int foo()' member provided");
//}
static void static_test() //This does not work. No compile time error.
{
static_assert(std::is_same<decltype(T::foo()), int>::value, "ERROR: No 'static int foo()' member provided");
}
};
class Good : public Base<Good> {
public:
static int foo() { return 42; };
};
class Bad : public Base<Bad> {
public:
static double foo() { return 42; };
};
int main()
{
Good g;
Bad b;
}
不知道我是否理解正确,但我觉得你想的太复杂了。让编译器为您想要生成的特殊成员生成定义的解决方法是声明它们 default
:
struct foo {
~foo() {} // prevents the compiler to generate move constructor
foo(foo&&) = default; // compiler generates a move constructor
};
您所拥有的是 class 需要实现的概念。您可以在 class 的定义之后简单地检查它,可能最简单的是 static_assert
:
template<typename T>
static constexpr bool assert_is_fooable() {
static_assert(std::is_same<decltype(T::foo()), int>::value, "ERROR: No 'static int foo()' member provided");
static_assert(condition_2(), "ERROR: condition 2");
// More specific error messages given above, this is always
// true so it can be used in a static_assert
return true;
}
class Good {
public:
static int foo() { return 42; };
};
static_assert(assert_is_fooable<Good>());
即使 class 未在其他任何地方使用,它也能正常工作。您还可以将断言放在使用 Good
的地方,期望它具有 static int foo()
。
这使得 class 可以被简单地破坏并且不会抑制移动构造函数或移动赋值运算符,因为它实际上并没有修改 class.
我想确保一些派生的 classes 实现了一个静态方法并发现了这个 SO 问题:Ensure derived class implements static method 最佳答案使用 CRTP 来解决 static_assert
的问题在基础 class 析构函数中确保模板参数类型实现 static int foo(int)
.
但是,正如对答案的评论所指出的“这个答案有一个小问题:写出析构函数会导致禁用移动构造函数和移动赋值运算符的生成。它还阻止了对象从 trivially_destructible。所以,虽然它有效,但这种方法有缺点(这些缺点适用于其他特殊成员)。” – @Matthieu M
有没有办法避免这种不利影响?我试过将 static_assert
移动到 Base
的成员函数和静态成员函数,但在这两种情况下,当派生的 class 不产生编译时错误'实施 static int foo()
。这是我一直在使用的代码(根据上面的 SO 线程调整):
#include <type_traits>
template <class T>
class Base {
public:
//~Base() //This works as expected! Compile error because Bad doesn't implement static int foo()
//{
// static_assert(std::is_same<decltype(T::foo()), int>::value, "ERROR: No 'static int foo()' member provided");
//}
static void static_test() //This does not work. No compile time error.
{
static_assert(std::is_same<decltype(T::foo()), int>::value, "ERROR: No 'static int foo()' member provided");
}
};
class Good : public Base<Good> {
public:
static int foo() { return 42; };
};
class Bad : public Base<Bad> {
public:
static double foo() { return 42; };
};
int main()
{
Good g;
Bad b;
}
不知道我是否理解正确,但我觉得你想的太复杂了。让编译器为您想要生成的特殊成员生成定义的解决方法是声明它们 default
:
struct foo {
~foo() {} // prevents the compiler to generate move constructor
foo(foo&&) = default; // compiler generates a move constructor
};
您所拥有的是 class 需要实现的概念。您可以在 class 的定义之后简单地检查它,可能最简单的是 static_assert
:
template<typename T>
static constexpr bool assert_is_fooable() {
static_assert(std::is_same<decltype(T::foo()), int>::value, "ERROR: No 'static int foo()' member provided");
static_assert(condition_2(), "ERROR: condition 2");
// More specific error messages given above, this is always
// true so it can be used in a static_assert
return true;
}
class Good {
public:
static int foo() { return 42; };
};
static_assert(assert_is_fooable<Good>());
即使 class 未在其他任何地方使用,它也能正常工作。您还可以将断言放在使用 Good
的地方,期望它具有 static int foo()
。
这使得 class 可以被简单地破坏并且不会抑制移动构造函数或移动赋值运算符,因为它实际上并没有修改 class.