ChatGPT解决这个技术问题 Extra ChatGPT

C++ template constructor

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

I would echo Johannes question. Why? There could be a better technique if we understand what you are trying to do.
@Loki It would be nice to have if generating something from a sequence of inputs (like vector's templated iterator constructor).
@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.

J
James McNellis

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.


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

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

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.
J
Johannes Schaub - litb

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.


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..).
Y
Yakk - Adam Nevraumont
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>{});

s
sehe

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


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_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.
T
Tolli

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


J
Joshua Chia

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.


u
user2616927

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.
v
vrqq

Just simple to add a dummy variable like

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