c++ - Invalid template instantation and the metaprogram compiles fine? -
i working on simple solution common "conditional on ill-formed types" problem (like this yesterday question).
in codebase have template hold uninstanced templates , instance them later. this:
template<template<typename...> class f> struct lazy {}; namespace impl { template<typename l , typename... args> struct lazy_instance; template<template<typename...> class f , typename... args> struct lazy_instance<lazy<f>,args...> : public identity<f<args...>> {}; } template<typename l , typename... args> using lazy_instance = typename impl::lazy_instance<l,args...>::type;
where identity
identity metafunction.
used follows:
using vector = lazy<std::vector>; using int_vector = lazy_instance<vector,int>;
so solution comes mind wrap 2 targets of conditional on way, , instantiate result of conditional, selected template instanced. purpose, have modified lazy
, impl::lazy_instance
allow pass template parameters @ lazy
instantation point:
template<template<typename...> class f , typename... args> struct lazy {}; namespace impl { template<typename l , typename... args> struct lazy_instance; template<template<typename...> class f , typename... args , typename... iargs> struct lazy_instance<lazy<f,args...>,iargs...> : public identity<f<args...>> {}; }
note in case lazy_instance
takes template parameters too, ignored. have donde on way have same interface both usage cases.
so our main problem, evaluation of conditional selection of potentially ill-formed types achieved follows:
using ok = lazy_instance<typename std::conditional<true, lazy<foo,int>, lazy<foo,bool> >::type >;
where foo
template bool
instantation ill-formed, example:
template<typename t> struct foo; template<> struct foo<int> {};
it seems work, isn't? great. couple of minutes later changed boolean flag false
, , surprisingly works too! if foo<bool>
specialization not defined!
also metaprogram has static_assert
bellow check if evaluation of conditional successfull:
static_assert( std::is_same<ok,foo<int>>::value , "mmmmm..." );
when changed condition true
false
, changed test see whats happening there:
static_assert( std::is_same<ok,foo<bool>>::value , "mmmmm..." );
and metaprogram passes test too! explicit instantation of foo<bool>
, , ok
, should alias instance.
have checked there no "no matching specialization foo<bool>
" until declare variable of type ok
: ok anok;
i'm working clang 3.4, on c++11 mode (-std=c++11
). question is: whats happening here? behaviour correct or llvm bug?
edit: here sscce running @ ideone. uses gcc 4.8.1, seems has same behaviour.
long story; short.
you not instantiating foo<bool>
in following expression:
std::is_same<ok, foo<bool>>::value;
when implicit instantiation occur?
14.7.1
implicit instantiation[templ.inst]
5)
class template specialization implicitly instantiated if class type used in context requires completely-defined object type or if completeness of class type might affect semantics of program.
7)
if implicit instantiation of class template specialization required , template declared not defined, program ill-formed.
what above text says class template implicitly instantiated when used in context requires defined, such when declaring object of said template, or when trying access inside it.
checking if 1 type same not count such context, since merely comparing 2 names.
when completely-defined object required?
the standard makes reference "completely-defined" in several different locations, when explicitly says such object required.
the easiest definition of when need completely-defined object reading following, explains isn't.
3.9p5
types[basic.types]
a class has been declared not defined, or array of unknown size or of incomplete element type, incompletely defined object type. incompletely-defined object types , void types incomplete types (3.9.1). objects shall not defined have incomplete type.
the wording above states long don't declare object of incomplete-type, in clear; ie. our template not implicitly instantiated.
see below example (c) , (d) tries create object of incomplete-type, both (a) , (b) legal since don't cause implicit instantiation.
template<class t> struct a; typedef a<int> a_int; // (a), legal a<int> * ptr; // (b), legal a<int> foo; // (c), ill-formed; trying declare object of incomplete-type a<int>::type baz; // (d), ill-formed; trying reach definition of `a<int>`
Comments
Post a Comment