#include <type_traits> template<class T> struct A { template<class=typename std::enable_if<std::is_same<T,int>::value>::type> A(A const&){} }; constexpr bool b = std::is_abstract<A<double>>::value; $ g++ -std=c++0x n.cc -c n.cc: In instantiation of 'struct A<double>': /tmp/gcc/inst/lib/gcc/x86_64-unknown-linux-gnu/4.7.0/../../../../include/c++/4.7.0/type_traits:530:12: required from 'struct std::is_abstract<A<double> >' n.cc:7:47: required from here n.cc:5:3: error: no type named 'type' in 'struct std::enable_if<false, void>' I am not sure what is supposed to happen (that's why I tried), but this result doesn't seem right. Filed under C++ because is_abstract directly forwards to the __is_abstract builtin, but feel free to reassign to libstdc++ if you think the problem is there somehow. I first tried it with is_copy_constructible (which indirectly calls is_abstract through is_destructible) to check the value it would give (clang+libc++ says is_copy_constructible is true).
(In reply to comment #0) > #include <type_traits> > template<class T> > struct A { > template<class=typename > std::enable_if<std::is_same<T,int>::value>::type> > A(A const&){} > }; > constexpr bool b = std::is_abstract<A<double>>::value; I *think* the compiler is right to reject this as it currently does, we have *no* sfinae here. When you instantiate A<double>, the declaration of the template constructor is also instantiated, but at that point A<double> is an incomplete type. IMO you need one further indirection, e.g. template<class T> struct A { template<class U = T, class = typename std::enable_if<std::is_same<U, int>::value>::type > A(A const&){} }; Btw.: Neither of these forms can ever prevent the "real" copy constructor to be declared, defined, and used by the compiler. > I am not sure what is supposed to happen (that's why I tried), but this result > doesn't seem right. Filed under C++ because is_abstract directly forwards to > the __is_abstract builtin, but feel free to reassign to libstdc++ if you think > the problem is there somehow. Lets look what the compiler-intrinsic people say, above is my first guess on that.
(In reply to comment #1) > IMO you need one further indirection, e.g. Ah, yes, makes sense (although clang accepts both versions). > Btw.: Neither of these forms can ever prevent the "real" copy constructor to be > declared, defined, and used by the compiler. I was experimenting with it because I don't understand why this code (your fixed version) is valid if that declaration has no effect... (well, it does remove the implicit A(), but that doesn't count) Maybe I should ask for a warning?
(In reply to comment #1) > When you instantiate A<double>, the declaration of the template constructor is > also instantiated, but at that point A<double> is an incomplete type. I just recognize that the last part of this is a bit misleading, please read this as: "When you instantiate A<double>, the declaration of the template constructor is also instantiated, but this turns out to be an ill-formed signature" The argument in regard to type-completeness was intended to point to the library specification, which requires A<double> to be complete, which means that A<double> may be instantiated including it's member declarations, which again is the cause of the error, because we have no sfinae situation here. In regard to the __is_abstract builtin question it seems that in simple cases like these (no dependent base classes involved), it may be possible to implement the intrinsic without instantiating A<double>, but maybe the current behavior is actually better, because it makes portable programming easier;-)
The issue with type_traits intrinsics vs instantiation came up recently, when I fixed an actual bug affecting __is_base_of. Note, if isn't clear already, that in the case of is_abstract, C++11 requires unconditionally completeness for T: we are treating all the traits having such type of precondition in an uniform way. All in all, I agree with Daniel about portability.
All right, now the is_abstract behavior is settled, do you think the fixed code provided by Daniel in comment #1 should produce a warning, since the declaration is absolutely useless (I may be missing something)? Or maybe there are legitimate meta-programming tricks I am not thinking of that would turn regular constructors into pseudo copy constructors to disable them?
(In reply to comment #5) > All right, now the is_abstract behavior is settled, do you think the fixed code > provided by Daniel in comment #1 should produce a warning, since the > declaration is absolutely useless (I may be missing something)? Ah, I did find a case where it was used: I added a A(A&) constructor to prevent the default A(A const&) from being generated, and then the template version was used when copying from const (only if T is int). Closing the bug as invalid, thanks for your answers.
(In reply to comment #5) > All right, now the is_abstract behavior is settled, do you think the fixed code > provided by Daniel in comment #1 should produce a warning, since the > declaration is absolutely useless (I may be missing something)? IMO a warning could be very useful here (at least in circumstances where the constructor is never reachable). > Or maybe there are legitimate meta-programming tricks I am not thinking of that > would turn regular constructors into pseudo copy constructors to disable them? While it seems that the current defect in regard to concept-constrained member functions mentioned in c++std-core-20783 is a defect, so that template<ObjectType T> class A { requires SomeConcept<T> A(const A&) {} }; is *intended* to work, I currently see no such chance for sfinae-constrained special-member functions - unless the new temploid nomenclature shows that in template<class T> struct A { template<class U = T, class = typename std::enable_if<std::is_same<U, int>::value>::type > A(A const&){} }; A<T>::A(A const&) is considered as a temploid as well. I stay tuned to see how "temploids" will be defined... Your suggested addition of a copy-constructor to non-const is surely useful in some cases, but I think the emulation is imperfect. Just consider that you try to copy from a source that is not const.
(In reply to comment #7) > IMO a warning could be very useful here (at least in circumstances where the > constructor is never reachable). Ok, reopening then. Not sure how easy it is to test for reachability in general, but there are certainly easy cases where it is doable. > While it seems that the current defect in regard to concept-constrained member > functions mentioned in c++std-core-20783 is a defect, so that > > template<ObjectType T> > class A { > requires SomeConcept<T> > A(const A&) {} > }; > > is *intended* to work, That would be great. I assume that when T doesn't satisfy SomeConcept, the compiler can still generate a default copy constructor (we can always have a deleted copy constructor with requires !SomeConcept<T> if we don't want it). > I currently see no such chance for sfinae-constrained > special-member functions - unless the new temploid nomenclature shows that in > > template<class T> > struct A { > template<class U = T, class = typename > std::enable_if<std::is_same<U, int>::value>::type > > > A(A const&){} > }; > > A<T>::A(A const&) is considered as a temploid as well. I stay tuned to see how > "temploids" will be defined... Looks interesting, although since we're talking about a future standard (at least I assume that's what you are talking about? Or are temploids coming up as a bugfix for C++11?), I'd rather write (see around c++std-ext-11764): static if(std::is_same<T,int>()) A(A const&){ /* special code */ } > Your suggested addition of a copy-constructor to non-const is surely useful in > some cases, but I think the emulation is imperfect. Just consider that you try > to copy from a source that is not const. I completely agree, I was just trying to see if there was any possibility for the templated "copy" constructor to have any effect (not even necessarily a useful one). If there had been none, a warning was definitely warranted.
(In reply to comment #8) > Looks interesting, although since we're talking about a future standard (at > least I assume that's what you are talking about? Or are temploids coming up as > a bugfix for C++11?) The term "temploid" will very probably be introduced for C++11 already, we have a lot of core issues that could be resolved much easier with that concept (I'm not referring here to language-concepts, just to make that clear).
The name temploid got replaced by "templated entity", see [temp.pre].