154

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)?

3
  • 1
    I would echo Johannes question. Why? There could be a better technique if we understand what you are trying to do. Commented Oct 18, 2010 at 18:24
  • 4
    @Loki It would be nice to have if generating something from a sequence of inputs (like vector's templated iterator constructor). Commented Aug 6, 2013 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. Commented Jul 10, 2018 at 13:03

10 Answers 10

131

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.

Sign up to request clarification or add additional context in comments.

3 Comments

It MAY be possible with qualifed constructor call, but seems does not work: Foo<int>::Foo<short>();
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: 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.
50

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(...);
    }
...        
};

5 Comments

But what about normal objects.
@Martin: I think this could also return by value (a non-pointer). RVO should take care of eliminating the copy anyway.
create() does not have to do dynamic allocation. Just return Foo(...); Thanks @Samuel_xL. This turned out to be a great idea for me.
Unfortunately, factory methods do not return xref values.. xref can be used with && with additional std::move.. if they did/could..
I don't get. How does it call a templated constructor with an empty parameters list? It seems to call regular one.
30
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>{});

5 Comments

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 No, which is why I write them. Boost Hana has value-based metaprogramming if I recall correctly, which is close?
There exists a nice trick for a) more performance (constexpr) and b) avoiding the need to explicitly instantiate an object using {}: Use a templated inline constexpr object like template<typename _Tp> inline constexpr in_place_type_t<_Tp> in_place_type{}; in <utility> header. Check the example on cppreference where they use std::in_place_type<std::string> to pass a constexpr tag object without explicit instantiation "{}".
@phinz Do you have proof of more performance, or do you just suspect?
@Yakk-AdamNevraumont It is clear that constexpr is easier to optimize but to be honest I think that most compilers will optimize away both objects completely in this case. But why else should in_place_type be constexpr if it was not meant to be an optimization hint for compilers?
28

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.

2 Comments

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.
@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..).
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

3 Comments

Funny thing is that if you declare sometihng like template <typename T> X(const X&); then it still will not be recognized as copy constructor, and standard copy-constructor will be created.
@j_kibik: Yes, the same is about templated assignment
...and default ctors. A class declared as struct S { template<typename T> 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.
5

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>{});

2 Comments

Instead of std::in_place_type_t<MyType>{} one should use std::in_place_type<MyType>, it's a templated inline constexpr object defined exactly for this purpose, see here for an example using std::in_place_type<std::string>.
@phinz This is accurate, thank you for the correction.
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.)

Comments

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.

Comments

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
    }
.
.
.
};

1 Comment

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.
0

Just simple to add a dummy variable like

class A {
  template<typename T>
  A(const T&, int arg1, int arg2);
}

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.