问题
Is there a way to static_assert that a type T is Not complete at that point in a header? The idea is to have a compile error if someone adds #includes down the road in places they should not be.
related: How to write `is_complete` template?
Using that link's answer,
namespace
{
template<class T, int discriminator>
struct is_complete {
static T & getT();
static char (& pass(T))[2];
static char pass(...);
static const bool value = sizeof(pass(getT()))==2;
};
}
#define IS_COMPLETE(X) is_complete<X,__COUNTER__>::value
class GType;
static_assert(!IS_COMPLETE(GType),"no cheating!");
unfortunately this gives "invalid use of incomlete type" error, d'oh. Is there a way to assert on the negation?
回答1:
Here is a function using expression SFINAE based on chris proposal which allows checking whether a type is complete yet.
My adoption needs no includes, errors-out when the required argument is missing (hiding the argument was not possible) and is suitable for C++11 onward.
template<typename T>
constexpr auto is_complete(int=0) -> decltype(!sizeof(T)) {
return true;
}
template<typename T>
constexpr bool is_complete(...) {return false;}
And a test-suite:
struct S;
bool xyz() {return is_complete<S>(0);}
struct S{};
#include <iostream>
int main() {
std::cout << is_complete<int>(0) << '\n';
std::cout << xyz() << '\n';
std::cout << is_complete<S>(0);
}
Output:
1
0
1
See live on coliru
回答2:
Passing a reference through ...
doesn't work.
5.2.2/7:
When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking
va_arg
(18.10). [note skipped — n.m.] The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the argument expression. An argument that has (possiblycv
-qualified) typestd::nullptr_t
is converted to typevoid*
(4.10). After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer to member, or class type, the program is ill-formed.
Here's a kind-of-working solution hastily adapted from @chris's comment:
#include <iostream>
#include <utility>
namespace
{
template<typename T, int>
constexpr auto is_complete(int) -> decltype(sizeof(T),bool{}) {
return true;
}
template<typename T, int>
constexpr auto is_complete(...) -> bool {
return false;
}
}
#define IS_COMPLETE(T) is_complete<T,__LINE__>(0) // or use __COUNTER__ if supported
struct S;
static_assert(IS_COMPLETE(int), "oops 1!");
static_assert(!IS_COMPLETE(S), "oops 2!");
struct S {};
static_assert(IS_COMPLETE(S), "oops 3!");
来源:https://stackoverflow.com/questions/25796126/static-assert-that-template-typename-t-is-not-complete