How to call template constructor?



  • Here is the class with template constructor:

    class C
    {
    private:
    	int x;
    public:
    	template<int X> C(void):x(X){;}	
    };
    

    How to call this constructor? This does not work:

    C c<10>;
    C<10> c;
    

    😞



  • AFAIK it is not possible. But you can do something like this

    class C
    {
    private:
        int x;
        C(int X) : x(X) {}
    public:
        template<int X> static C getC() { return C(X); }
    };
    
    int main()
    {
        C elem(C::getC<2>());
        return 0;
    }
    


  • That's right, constructors can't ever be called with template parameters. The only way of invoking such a constructor is by letting the compiler deduce the template arguments from the constructor arguments. This also means that a template constructor with no parameters can never be called at all.



  • Ok.

    The question is: How I can pass a compile-time constant to the constructor?
    The constant should still be the compile-time constant inside the constructor.



  • SAn schrieb:

    Ok.

    The question is: How I can pass a compile-time constant to the constructor?
    The constant should still be the compile-time constant inside the constructor.

    also erstmal solltest du Deutsch lernen 😉



  • ^^^^^^, I decided to use German C++ forum for two reasons:

    1. It was at the first place in Google search (query "C++ Forum");
    2. I think German people are very "disciplined", so they should write the most correct (according to ANSI standard) C++ programs.

    I do not know German language (I am from Russia). I decided that English will be OK. I can help beginner programmers here (I have perfect automatic translator from German to Russian), but I do no know if they know English.

    I have been to Germany. There are beautiful places there:
    http://keep4u.ru/imgs/b/071213/eb/ebd7c154670bae5fdf.jpg
    http://www.photosight.ru/photo.php?photoid=2072575&ref=author
    http://www.photosight.ru/photo.php?photoid=1721430&ref=author



  • Don't bother about the unregistered "Troll" 😉

    You could pass the constant via an empty pseudo-object that is an argument to the template-constructor (so the compiler can deduce the template argument from the real argument):

    template< int N > struct value_t {};
    
    class C
    {
    public:
        template< int N >
        C( value_t< N > )
        {
            // access N
        }
    };
    
    C c1( value_t< 12 >() );
    C c2( value_t< 100 >() );
    

    EDIT: Some optimizations.



  • LordJaxom, thanks a lot. This works for me.



  • Hi,

    I was intrigued by the question so I tried to get the code to work. Obviously, I failed. However, I'd like to know *why* I failed.

    Consider the following class and constructor:

    struct C {
        int x;
        C() : x() { }
    };
    

    Now, the following instantiation works on both MSVC 9 as well as GCC 4.2 and as far as I understand the standard, it's legal:

    int main() {
        C c = C::C();
    }
    

    Analogously, I believe the following code should work; that is, I see no reason (in the standard or elsewhere) that it differs from the one above:

    struct C {
        int x;
        template <int X> C() : x(X) { }
    };
    
    int main() {
        C c = C::C<10>();
    }
    

    However, the code fails in both compilers. Here's what they say.

    GCC: 'C' is not a template. No matching function for call to 'C::C()'
    MSVC: 'C::{ctor}': cannot take address of this member function

    Can anyone explain?



  • Konrad Rudolph schrieb:

    Now, the following instantiation works on both MSVC 9 as well as GCC 4.2 and as far as I understand the standard, it's legal:

    int main() {
        C c = C::C();
    }
    

    In german for Konrad:
    Bei Sachen ob illegal oder nicht würde ich immer den Comeau zu rate ziehen: http://www.comeaucomputing.com/tryitout/ Einfach Code unten rein und "Compile".

    "ComeauTest.c", line 7: error: a constructor or destructor may not have its address
              taken
          C c = C::C();
    

    Standard 12.1.12 schrieb:

    No return type (not even void) shall be specified for a constructor. A return statement in the body of a constructor
    shall not specify a return value. The address of a constructor shall not be taken.

    Im Falle C c = C(); erzeugst du ja im schlimmsten Fall ein temporäres Objekt das danach in c kopiert wird.
    Wenn du schreibst C::C() bezeichnet man das glaube ich als einen "qualifizierten" Aufruf, d.h. du versuchst die Funktion( den Konstruktor ) direkt aufzurufen, was natürlich fehlschlägt.

    Zudem definiert man ja mit dem Ausdruck C::C() den C'tor außerhalb der Klasse, kann sein, dass das damit auch was zu tun hat.

    [ Selbstgestrickte Theorie -> camper verbessert das schon 😉 ]



  • Selbstgestrickte Theorie -> camper verbessert das schon

    ROFL

    BTW: Wir sollten camper den Ehrentitel "C++ Standard Bot" geben (analog zu "Bible Bot" und ähnlichen Einrichtungen) 😃



  • I have once learned that in C++ it is impossible to call any constructor directly, except via placement-new. Therefore, as I understand the standard, the first example should be illegal as well.

    I think the quoted section of the standard confirms this, since you need an address for any function call (and since a constructor doesn't have a return value, it's result couldn't be used for an initialization anyways).



  • LordJaxom schrieb:

    I have once learned that in C++ it is impossible to call any constructor directly, except via placement-new. Therefore, as I understand the standard, the first example should be illegal as well.

    Yes, of course. KasF gave the correct explanation. Thanks to you both.


Log in to reply