C++ template constructor - c++

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

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.

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

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.

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

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

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

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.

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

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

Just simple to add a dummy variable like
class A {
template<typename T>
A(const T&, int arg1, int arg2);
}

Related

Passing unique_ptr<Derived<T>> to a function

I need to pass a unique pointer to a derived template class to a function that takes a unique base template class, like this:
template <typename T>
class Base {};
template <typename T>
class Derived : public Base<T> {};
template <typename T>
void foo(std::unique_ptr<Base<T>>){}
//or
template <typename T>
class MyClass{
public:
MyClass(std::unique_ptr<Base<T>> arg) : _arg(std::move(arg)) {}
private:
std::unique_ptr<Base<T>> _arg;
};
int main()
{
auto b = make_unique<Derived<int>>();
foo(std::move(b));
MyClass mc(std::move(b))
}
Why is this not working and how can I fix it?
I get an error:
'void foo1<T>(std::unique_ptr<Base<T>,std::default_delete<Base<T>>>)': cannot convert argument 1 from 'std::unique_ptr<Derived<int>,std::default_delete<Derived<int>>>' to 'std::unique_ptr<Base<T>,std::default_delete<Base<T>>>'
but it work
auto derived = std::make_unique<Derived<int>>();
std::unique_ptr<Base<int>> base = std::move(derived);
C++ doesn't deduce template arguments in this situation. You can specify <int>, and that will succeed.
foo<int>(std::move(b)); // fine
MyClass<int> mc(std::move(b)); // fine
See it on coliru
You can't have template argument deduction also consider implicit conversions, at least not in most situations. Normally the argument type must match the parameter type exactly for deduction of a template argument to be possible (in this case to deduce T), but std::unique_ptr<Base<int>> and std::unique_ptr<Dervived<int>> are not the same type.
As the other answer suggests you can explicitly specify the template argument instead of trying to have it be deduced.
If you want to automate this without having to add anything to Derived or Base you can however make use of one of the exceptions to the general rule above. If the template parameter is a reference-to or pointer-to base of the argument type, then it may (with certain conditions) still be used for deduction:
// Here an exception to the deduction rules applies
// and `Base<T>*` can be deduced against a pointer `X*`
// if `X` is (uniquely) derived from a `Base<T>`
template<typename T>
auto as_base_ptr(Base<T>* p){
return p;
}
template<typename X>
auto to_base_unique_ptr(std::unique_ptr<X> p) {
using base_type = std::remove_pointer_t<decltype(as_base_ptr(std::declval<X*>()))>;
return std::unique_ptr<base_type>(std::move(p));
}
template <typename T>
void foo(std::unique_ptr<Base<T>>){
}
template <typename X>
void foo(std::unique_ptr<X> p){
foo(to_base_unqiue_ptr(std::move(p)));
}
But even simpler you can ask yourself whether you really need to have the function foo take std::unique_ptr<Base<T>> specifically (e.g. because you need access to T) or whether std::unique_ptr<X> wouldn't already be enough.

How can I call variadic template constructor in c++?

I am learning c++ template technique.
I made a constructor with variadic template augments like following.
The class is simplified very much, so it does not have meaning.
However I could not call the function. Compiler tells me that it cannot call constructor directly.
How can I call it?
#include <utility>
class TemplateVariadicAugments {
public:
template <typename FutureInnterTemplateClass, typename... Args>
TemplateVariadicAugments(Args&&... args) : value_(std::forward<Args>(args)...) {}
virtual ~TemplateVariadicAugments() = default;
int value_;
};
void test_variadic_template_augments(void) {
TemplateVariadicAugments a = TemplateVariadicAugments::template TemplateVariadicAugments<int, int>(1);
}
In the form you wrote it, there is no way to call the constructor. First, in C++ you cannot call a constructor by it's name, even in trivial cases:
class A
{
public:
A() {}
};
void foo()
{
A::A(); // Illegal.
}
Then, as you can't call the constructor directly, you can't instantiate the template explicitly, so all template arguments must be deduced. But in your case FutureInnterTemplateClass cannot be deduced, as it's not used anywhere in the constructor.
The solution is to remove redundant argument from the constructor:
template <typename... Args>
TemplateVariadicAugments(Args&&... args) : value_(std::forward<Args>(args)...) {}
Now an object may be constructed as follows:
TemplateVariadicAugments obj(1);
and Args in this case wil lbe correctly deduced to int.
But in this case it's unclear what did you want to say with variadic template argument, as if you construct an object like this:
TemplateVariadicAugments obj(1, 2);
your value_ member initialization will become equivalent ti this code:
int value_(1, 2);
which is obviously ill-formed.

c++ template class objects compatible

I have a template class
template<int N>
class xyz{
some code ....
};
if I do not use N inside the class, then all objects of this class should be compatible irrespective of the template value. But its not.
For example, if I say xyz<20> a and then xyz<30> b(a), the compiler gives an error.
Why is this so?
Because they are different types. Even for this empty class template
template <int N> struct Foo {};
Foo<1> is a different type to Foo<2>. When such a template is instantiated with a template parameter, it creates a distinct class, irrespective of whether the template parameter is used in the code of the class. A class template is a recipe (a template) for building a class according to some (template) parameters.
Now, if you want to be able to construct one Foo instnatiation from another, then you can add an implicit converting constructor:
template <int N>
struct Foo
{
template <int M> Foo(const Foo<M>& rhs) {}
};
Then you can implicitly convert between one and the other:
Foo<42> a;
Foo<1> b (a);
Foo<99> c;
c = b;
Each time you use a different value of N, the compiler will create a new class definition.
Using template value or not change nothing.
it's the same for function parameters :
int foo(void) { // foo is of type `int (*)()`
return 1;
}
int bar(int not_used) { // bar is of type `int (*)(int)`
return 1;
}
bar don't use parameter, but it hasn't the same signature as foo.
Like you can't assign foo or bar to a same variable (because their types differs), you can't mix instances of xyz<0> and xyz<1>.
If you want to do this, you shoud consider using a classic inheritance.
Template type equivalence rules are explicitly written out in the Standart (paragraph 14.4). One rule states:
Two template-ids refer to the same class or function if
their corresponding non-type template arguments of integral or enumeration type have identical values
Thus, different numeric template arguments will yield different types, regardless whether they are actually used or not. In the latter case you might want to use template copy constructor:
template<int N>
class xyz{
template<int M>
xyz::xyz(const xyz<M>&);
};
How do you want compiler to prove that?
Consider:
template<int N>
class xyz{
void foo () {external_function (N);}
};
Do you suggest compiler to go and check what external_function does?
Besides having compiler produce compatible types on the grdounds of N not being used would have been a maintanence nightmare.
I assume you mean "copy-constructible and assignable from each other" when you say compatible.
You will need to define the copy-constructor and assignment operator
to handle classes instantiated with arbitrary values of int.
template<int N>
class Foo {
public:
template<int NO>
Foo(const Foo<NO>& other) {
// do stuff
}
template<int NO>
Foo& operator=(const Foo<NO>& other) {
// do stuff
return *this;
}
};

C++: instantiate a templated class according to an argument

I often find the need to use the following pattern:
template<typename T>
class SomeClass : public Base {
SomeClass(const T& t) {...}
...
};
template<typename T>
SomeClass<T>* makeSomeClass(const T& t) {
return new SomeClass<T>(t);
}
And to use it:
Base* = makeSomeClass(123);
This is useful when I don't want to explicitly specify T because it is a very complex (function types, etc') and the function argument can deduce the type implicitly.
Is there a way to do this without the extra "make" function? Why does template deduction work only in function arguments and not in constructor arguments?
No, there is no way to do this without an extra make function.
The reason it doesn't work with constructors is because it would be ridiculously complicated. Consider this:
template <typename T>
struct Foo
{
Foo(const T& val) { ... }
Foo(const Foo<T>& other) { ... } // Copy constructor
};
Foo<int> x;
What if I then call:
Foo(x);
Does that give me a Foo< Foo<int> > or am I calling the copy constructor for a Foo<int>?
It would be ambiguous in too many places, so the extra function is necessary.
Note that you can automate the create of make functions a little by using template templates:
template <template <typename> class TemplateClass, typename Type>
TemplateClass<Type> make(const Type& x)
{
return TemplateClass<Type>(x);
}
Then you can use:
make<SomeClass>(123); // returns a SomeClass<int>
It does work in constructor arguments, if the constructor is itself a template. The difference is that when you use your helper, you're using a function template, where the compiler can deduce the type. Without the helper, you're using a class template, where the compiler would have to somehow deduce the type before calling the (non-template) constructor.
Is there a way without the extra function? No there isn't. Why the deduction works only for functions? Because with functions you actually provide arguments. If it were allowed for classes, then the only way to deduce the template parameters would be in case when a constructor was called for initialization, which makes lots of additional rules and exceptions and complicates things,

Minor question regarding templeted functions in templated class

I am trying to understand some C++ syntax:
template<class T>
class Foo
{
Foo();
template<class U>
Foo(const Foo<U>& other);
};
template<class T>
Foo<T>::Foo() { /*normal init*/ }
template<class T>
template<class U>
Foo<T>::Foo(const Foo<U>& other) { /*odd copy constructed Foo*/ }
So, I wrote code like this, and it happens to compile fine in windows and linux. What I don't understand is why the copy constructor has two templates defined as so. Basically, I had to expirment a bit before I found the correct syntax and I would like to know why that particular syntax is correct, and not something like template<class T, class U>.
The first template ( with parameter T) says that the class is templated with a parameter T.
The second template (with parameter U) says that the member function of the templated class (with parameter T) is templated with parameter U - that is the constructor.
In fact, here you have a template class that will generate as many copy constructor as types used as parameter of the constructor.
In the specific case of copy constructor, you shouldn't do this but instead :
template<class T>
class Foo
{
Foo();
Foo(const Foo<T>& other);
};
template<class T>
Foo<T>::Foo() { /*normal init*/ }
template<class T>
Foo<T>::Foo(const Foo<T>& other) { /*odd copy constructed Foo*/ }
Because in you example it's not copy constructor but constructor that take type U as parameter: a convertion constructor... that is hard to predict.
It has to have separate template clauses for each template that is involved. Here, two templates are involved, that all deserve their (non-empty) template clauses:
The class template Foo
The constructor template
Consider this case which fails because of the ambiguity as to where the parameter U belongs to
template<typename T>
struct A {
template<typename U> void f();
};
template<typename T, typename U>
void A<T>::f() { }
Now, what is up with the parameter U? Sure the compiler could guess it could belong to f, but guesswork is not what the compiler likes :) The existing rule says that depending on the nesting of templates, template clauses appear in the right order. Everything is clear then.
Even if one comes up with a rule how to match the parameters to arguments of the templates involved (so far i don't see a real difficulty in doing that), it would be inconsistent. Because as of now, one template clause lists all parameters that the corresponding template accepts. Much like a function parameter list. If we would put everything into one clause, that clear semantic could be broken - not to mention that when we put the definition into the class again, all of a sudden the template would get its own clause:
// provides arguments for A's parameters, then for f ones
// when it's called
A<int> a;
a.f<bool>();
It's much more natural when we have separate template clauses that catch each their own arguments. So, the syntax for the above wrong definition is
template<typename T>
template<typename U>
void A<T>::f() { }
Now, also the reader of the code immediately sees that this is a definition of a member template, and not a (potential accidentally declared but unused) second parameter for A.