c++ - Custom compile error message when undefined subtype is accessed -


i have types have sub-types same name each:

struct typea {     typedef int subtype; }; struct typeb {     typedef float subtype; }; 

and types don't have sub-type used in same context:

struct typec {     // (no subtype defined) }; 

how can add dummy sub-type gives custom compile error message?

my (so far unsuccessful) attempt is:

struct typec {     struct subtype {         static_assert(false, "attempt access non-existent subtype of typec.");     }; }; 

but static_assert(false, ...) can't work, compiler throws error if type never accessed.

how can delay evaluation of static_assert time when type being accessed?

a failed attempt introduce dummy enum , construct expression out of it:

enum { x }; static_assert(x != x, "..."); 

concrete use case: have class-template list defined sub-types head , tail if non-empty, , should give error if these sub-types used if empty:

template<typename...> struct list;  // empty list: template<> struct list<> {     struct head { static_assert(false, "attempt access head of empty list."); };     struct tail { static_assert(false, "attempt access tail of empty list."); }; };  // non-empty list: template<typename head, typename ...tail> struct list<head, tail...> {     typedef head head;     typedef list<tail...> tail; }; 

if leave out types head , tail, when accessing e.g. 3rd element of list has size 2 code list<int,int>::tail::tail::head gives not nice message (g++ 4.7.2): 'head' not member of 'list<int>::tail {aka list<>}'

// empty list: template<typename... args> struct list {     struct head {static_assert(sizeof...(args) != 0, "attempt access head of empty list."); };     struct tail {static_assert(sizeof...(args) != 0, "attempt access tail of empty list."); }; };  // non-empty list: template<typename head, typename ...tail> struct list<head, tail...> {     typedef head head;     typedef list<tail...> tail; }; 

edit: problem touches on 3 aspects of how c++ templates work:

  1. (§14.7.1 [temp.inst]/p1) unless class template specialization has been explicitly instantiated (14.7.2) or explicitly specialized (14.7.3), class template specialization implicitly instantiated when specialization referenced in context requires completely-defined object type or when completeness of class type affects semantics of program. implicit instantiation of class template specialization causes implicit instantiation of declarations, not of definitions ... of class member functions, member classes, [...].
  2. (§14.7.1 [temp.inst]/p11) implementation shall not implicitly instantiate ... member class...of class template not require instantiation.
  3. (§14.6 [temp.res]/p8) if no valid specialization can generated template, , template not instantiated, template ill-formed, no diagnostic required.

3) means static_assert expression must depend on template argument, otherwise "no valid specialization" can generated template , program ill-formed, , compilers free report error (although don't have to). in above code, valid specialization can generated first template, such specialization never used because of partial specialization.

the solution given above relies on 1) , 2). 1) provides implicitly instantiating template specialization instantiates declarations (not definitions) of member classes, , 2) means compilers affirmatively prohibited attempting instantiate head or tail if 1 merely using implicitly instantiated list<>. note rule not apply if explicitly instantiate list<> template struct list<>;.

the solution in leemes's answer works because typedefs not require complete type , not trigger implicit instantiation of subtypeerrormessage<> under 1), , use of template argument in static_assert in subtypeerrormessage bypasses 3), valid specialization (i.e., subtypeerrormessage<true>) can generated template.

it's worth noting in both cases instantiation rules mean it's still legal use list<>::head or typec::subtype long don't use them in way requires complete type. int f(list<>::head & ) { return 0; } valid, though entirely meaningless since there's no way can call function. if don't define list<>::head @ all, however, compiler report (perhaps cryptic) error on code. that's trade-off prettier error messages :)


Comments

Popular posts from this blog

google api - Incomplete response from Gmail API threads.list -

Installing Android SQLite Asset Helper -

Qt Creator - Searching files with Locator including folder -