问题
Say I have a template class that makes multiple static_asserts:
template <class T>
class Foo
{
static_assert(!std::is_const<T>::value,"");
static_assert(!std::is_reference<T>::value,"");
static_assert(!std::is_pointer<T>::value,"");
//...<snip>...
}
Now say I have more template classes that need to make the same asserts.
Is there a way to make a static_assert
block reusable? A "static_assert function" if you will.
回答1:
One thing you can do is build a new trait that is a conjunction of the traits you want to check. Since you want the negation of all of those traits that would literally translate to
template<typename T>
using my_trait = std::conjunction<std::negation<std::is_const<T>>,
std::negation<std::is_reference<T>>,
std::negation<std::is_pointer<T>>>;
static_assert(my_trait<int>::value, "");
but having to use std::negation
for every trait is/can be a pain. You can get rid of that though using std::disjunction to get an "or" of all the traits and then just negate the value in the static assert like you do which gives you
template<typename T>
using my_trait = std::disjunction<std::is_const<T>,
std::is_reference<T>,
std::is_pointer<T>>;
static_assert(!my_trait<int>::value, "");
回答2:
You can just combine required traits into one with descriptive name:
template<typename T> using
is_fancy = ::std::integral_constant
<
bool
, (not std::is_const<T>::value)
and
(not std::is_reference<T>::value)
and
(not std::is_pointer<T>::value)
>;
and use it later:
static_assert(std::is_fancy<T>::value,"");
回答3:
I've seen a few good answers, using the conjunction. Unfortunately, these are really hard to debug. I've once had to debug an issue with my class stating: requirements met. This was a too long list to understand. I finally copied all underlying checks one by one.
When possible, I like to keep them split:
template<typename T>
struct CustomCheck {
static_assert(check<T>);
// ...
};
In your class, you only have to instantiate it to get the checking and a detailed error:
constexpr static CustomCheck<T> check{};
回答4:
You can define a constexpr bool
which does the evaluation at compile time:
template<typename T>
inline constexpr bool is_okay_type = !std::is_const<T>::value &&
!std::is_reference<T>::value &&
!std::is_pointer<T>::value;
Then either:
use it directly
static_assert<>
, as you did in your example:template<typename T> class MyClass { static_assert(is_okay_type<T>, "message"); public: //...code... };
or you can make conditional instantiation of the template class, depending on the template argument.
template<typename Type, typename Enable = void> class Class1; template<typename Type> class Class1<Type, std::enable_if_t<is_okay_type<Type>> > { //...code... };
来源:https://stackoverflow.com/questions/55799464/how-to-make-static-assert-block-re-usable-in-template-classes