tags:

views:

364

answers:

4

Traits classes can be defined to check if a C++ class has a member variable, function or a type (see here).

Curiously, the ConceptTraits do not include traits to check if a C++ class defines a default constructor or given constructor?

Can traits be used to check the constructor presence? If yes, how? If not, why it is not possible?

+1  A: 

Sorry for answering may own question.

Googling I have found that the actual reason we can not check if a class has constructor or a destructors is that, the known technique used to detect if a class has a member is based on taking the address of the member. But constructors and destructors have no name, we can not take the address of them.

If we can not take the address, I don't see a way to make the compiler react to a construction without instantiating it directly, but in this case there is no detection at compile time but an error.

So to answer my own question, I would say that with the current techniques it is not possible to detect them and compiler support is needed. But C++ has revealed a lot of surprises, and things that were not possible at a given time, were revealed are possible using another technique.

I hope a C++ language expert is reading that and can give a more clear explanation.

Vicente Botet Escriba
Maybe thats something worth posting on comp.lang.c++.moderated and posting results here?
Georg Fritzsche
Good Idea. I will do it.
Vicente Botet Escriba
A: 

MSDN says that the header defines has_default_constructor and such traits.

http://msdn.microsoft.com/en-us/library/bb982179.aspx

DeadMG
Yes, this can be the case of MSVC, but currently this is a C++0x feature, that it seems can be provided only by the compiler,i.e. we can not define it ourselves.
Vicente Botet Escriba
A: 

Concept Traits is no more maintained, but become part of Type Traits. And in docs of has_trivial_constructor and has_trivial_destructor, Boost authors explain clearly that compiler support is required to make this work.

Blaisorblade
Btw, the original Concept Traits docs document a ::boost::has_default_constructor<T>::value metatfunction to check what you need:http://neoscientists.org/~tschwinger/boostdev/concept_traits/libs/concept_traits/doc/#OperatorTraits
Blaisorblade
@Blais I'm not asking for has_trivial_constructor, but for has_default_constructor.
Vicente Botet Escriba
@Blais boost::has_default_constructor<T> do a compile error if T is a class or union and the default constructor is not accessible. So it is not really a useful trait in this case.
Vicente Botet Escriba
+1  A: 

I'm pretty new to SFINAE. Today it occurred to me to put a test expression inside a sizeof inside a template parameter in a function argument type.

According to N2634 this is not wrong, but highly unportable. (EDIT: appears to be compliant to C++0x FCD.) It can only return positive or fail to compile in GCC 4.2; GCC 4.5 scores a 3 out of 3 for my test cases.

The SFINAE rules were broadened (in this case) since C++03 in the FCD. New §14.8.2/8 (emphasis mine):

If a substitution results in an invalid type or expression, type deduction fails. An invalid type or expression is one that would be ill-formed if written using the substituted arguments. Access checking is not done as part of the substitution process. Consequently, when deduction succeeds, an access error could still result when the function is instantiated. Only invalid types and expressions in the immediate context of the function type and its template parameter types can result in a deduction failure. [ Note: The evaluation of the substituted types and expressions can result in side effects such as the instantiation of class template specializations and/or function template specializations, the generation of implicitly-defined functions, etc. Such side effects are not in the “immediate context” and can result in the program being ill-formed.

template< class T >
class is_default_constructible {
    template<int x>
    class receive_size{};

    template< class U >
    static int sfinae( receive_size< sizeof U() > * );

    template< class U >
    static char sfinae( ... );

public:
    enum { value = sizeof( sfinae<T>(0) ) == sizeof(int) };
};

class q { q(); };
class r { r(int); };

#include <iostream>
using namespace std;

int main() {
    cerr << is_default_constructible<int>::value << endl // outputs 1
        // fails to compile: access violation
        // FCD demands that access violations be unrecoverable
        // indeed, it's murky: q is default-constructible, but only "rarely"
        //<< is_default_constructible<q>::value << endl
        << is_default_constructible<r>::value << endl; // outputs 0
}
Potatoswatter
VC++2010 outputs 1, 1 :-(
James McNellis
This is exactly the problem. q is not default-constructible as the default constructor is not accessible, so the compile fails Hrrr.
Vicente Botet Escriba