147

I wish to have a non-template class with a template constructor with no arguments.

As far as I understand, it's impossible to have it (because it would conflict with the default constructor - am I right?), and the workaround is the following:

class A{
   template <typename U> A(U* dummy) {
   // Do something
   }
};

Maybe there is a better alternative for this (or a better workaround)?

Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
Yippie-Ki-Yay
  • 22,026
  • 26
  • 90
  • 148
  • 1
    I would echo Johannes question. Why? There could be a better technique if we understand what you are trying to do. – Martin York Oct 18 '10 at 18:24
  • 3
    @Loki It would be nice to have if generating something from a sequence of inputs (like vector's templated iterator constructor). – VF1 Aug 06 '13 at 22:50
  • @VF1 Exactly why I came here. My class holds a vector of enums and I'd like to initialize it with a sequence of some kind. A vector seems heavy-weight, particularly pre-brace-init (C++98 here). VAR_ARGS seems just terrible (even though it may be best). Passing a reference to an array seems ok. – Peter - Reinstate Monica Jul 10 '18 at 13:03

10 Answers10

128

There is no way to explicitly specify the template arguments when calling a constructor template, so they have to be deduced through argument deduction. This is because if you say:

Foo<int> f = Foo<int>();

The <int> is the template argument list for the type Foo, not for its constructor. There's nowhere for the constructor template's argument list to go.

Even with your workaround you still have to pass an argument in order to call that constructor template. It's not at all clear what you are trying to achieve.

James McNellis
  • 348,265
  • 75
  • 913
  • 977
  • 3
    It MAY be possible with qualifed constructor call, but seems does not work: Foo::Foo(); – John Aug 23 '12 at 09:03
  • 1
    But automatic type inference is still possible. As long as you are satisfied with automatic type inference, you can use a template constructor (of a non-template class). – updogliu Sep 01 '12 at 03:38
  • 5
    @updogliu: Absolutely. But, the question is asking about "a template constructor with no arguments" If there are no function arguments, no template arguments may be deduced. – James McNellis Sep 01 '12 at 03:39
47

You could use a templated factory function instead of a constructor:

class Foo
{
public:
    template <class T> static Foo* create() // could also return by value, or a smart pointer
    {
        return new Foo(...);
    }
...        
};
KeatsPeeks
  • 19,126
  • 5
  • 52
  • 83
  • But what about normal objects. – Martin York Oct 18 '10 at 16:08
  • 13
    @Martin: I think this could also return by value (a non-pointer). RVO should take care of eliminating the copy anyway. – UncleBens Oct 18 '10 at 16:17
  • 4
    create() does not have to do dynamic allocation. Just `return Foo(...);` Thanks @Samuel_xL. This turned out to be a great idea for me. – NoahR Feb 26 '13 at 05:08
  • Unfortunately, factory methods do not return xref values.. xref can be used with && with additional std::move.. if they *did/could*.. – user2864740 Feb 01 '20 at 03:09
  • 2
    I don't get. How does it call a templated constructor with an empty parameters list? It seems to call regular one. – Oleksa Aug 14 '20 at 19:38
28
template<class...>struct types{using type=types;};
template<class T>struct tag{using type=T;};
template<class Tag>using type_t=typename Tag::type;

the above helpers let you work with types as values.

class A {
  template<class T>
  A( tag<T> );
};

the tag<T> type is a variable with no state besides the type it caries. You can use this to pass a pure-type value into a template function and have the type be deduced by the template function:

auto a = A(tag<int>{});

You can pass in more than one type:

class A {
  template<class T, class U, class V>
  A( types<T,U,V> );
};
auto a = A(types<int,double,std::string>{});
Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524
  • I see these `types`, `tag`, `type_t` templates or variants of it quite often in all sorts of contexts. Is there something in `std` for this? – thorink Jan 19 '23 at 08:48
  • @thorink No, which is why I write them. Boost Hana has value-based metaprogramming if I recall correctly, which is close? – Yakk - Adam Nevraumont Jan 19 '23 at 13:54
27

As far as I understand, it's impossible to have it (because it would conflict with the default constructor - am I right?)

You are wrong. It doesn't conflict in any way. You just can't call it ever.

Johannes Schaub - litb
  • 496,577
  • 130
  • 894
  • 1,212
  • 2
    1. Actually, you can call the template ctor: `int *p; A a(p)`. 2. Prejudice or idealization ;-) There is no John Doe. There is nothing typical German... and definitely not in Johannes' words. If they sound humorless then just because C++ is humorless. – Andreas Spindler Sep 08 '16 at 10:12
  • 2
    @AndreasSpindler I meant that he can never call the constructor if it has no arguments but still a template parameter (applies only to C++03. C++11 has introduced default template parameter, which would allow calling it, of course, if the ctor has default arguments..). – Johannes Schaub - litb Sep 08 '16 at 16:04
19

Some points:

  • If you declare any constructor(including a templated one), the compiler will refrain from declaring a default constructor.
  • Unless you declare a copy-constructor (for class X one that takes X or X& or X const &) the compiler will generate the default copy-constructor.
  • If you provide a template constructor for class X which takes T const & or T or T& then the compiler will nevertheless generate a default non-templated copy-constructor, even though you may think that it shouldn't because when T = X the declaration matches the copy-constructor declaration.
  • In the latter case you may want to provide a non-templated copy-constructor along with the templated one. They will not conflict. When X is passed the nontemplated will be called. Otherwise the templated

HTH

sehe
  • 374,641
  • 47
  • 450
  • 633
Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
  • 1
    Funny thing is that if you declare sometihng like template X(const X&); then it still will not be recognized as copy constructor, and standard copy-constructor will be created. – j_kubik Jun 27 '11 at 17:28
  • @j_kibik: Yes, the same is about templated assignment – Armen Tsirunyan Jun 27 '11 at 17:30
  • 1
    ...and default ctors. A class declared as `struct S { template S() { } };` declares an "unreachable ctor". There is no way to deduce or pass the `T`. Nonetheless a default ctor is not generated since a user-defined ctor seems to exist. – Andreas Spindler Sep 09 '16 at 10:08
2

You could do this:

class C 
{
public:
    template <typename T> C(T*);
};
template <typename T> T* UseType() 
{
    static_cast<T*>(nullptr);
}

Then to create an object of type C using int as the template parameter to the constructor:

C obj(UseType<int>());

Since you can't pass template parameters to a constructor, this solution essentially converts the template parameter to a regular parameter. Using the UseType<T>() function when calling the constructor makes it clear to someone looking at the code that the purpose of that parameter is to tell the constructor what type to use.

One use case for this would be if the constructor creates a derived class object and assigns it to a member variable that is a base class pointer. (The constructor needs to know which derived class to use, but the class itself doesn't need to be templated since the same base class pointer type is always used.)

Tolli
  • 362
  • 5
  • 12
2

It is perhaps easier and more intuitive to rely on std::in_place_type_t<T> which is used in std::variant, std::any, etc for exactly the same purpose:

#include <utility>

class A {
   template <typename U>
   A(std::in_place_type_t<U>) {
       // Do something
   }
};

A a(std::in_place_type_t<MyType>{});
Pavel Kirienko
  • 1,162
  • 1
  • 15
  • 31
1

Here's a workaround.

Make a template subclass B of A. Do the template-argument-independent part of the construction in A's constructor. Do the template-argument-dependent part in B's constructor.

Joshua Chia
  • 1,760
  • 2
  • 16
  • 27
0

try doing something like

template<class T, int i> class A{

    A(){
          A(this)
    }

    A( A<int, 1>* a){
          //do something
    }
    A( A<float, 1>* a){
         //do something
    }
.
.
.
};
  • this can also be done with template functions by defining a non-template class, a template constructor which is called from a non-template default constructor. – user2616927 Oct 03 '13 at 20:31
0

Just simple to add a dummy variable like

class A {
  template<typename T>
  A(const T&, int arg1, int arg2);
}
vrqq
  • 448
  • 3
  • 8