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

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,

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

Semi-generic function

I have a bunch of overloaded functions that operate on certain data types such as int, double and strings. Most of these functions perform the same action, where only a specific set of data types are allowed. That means I cannot create a simple generic template function as I lose type safety (and potentially incurring a run-time problem for validation within the function).
Is it possible to create a "semi-generic compile time type safe function"? If so, how? If not, is this something that will come up in C++0x?
An (non-valid) idea;
template <typename T, restrict: int, std::string >
void foo(T bar);
...
foo((int)0); // OK
foo((std::string)"foobar"); // OK
foo((double)0.0); // Compile Error
Note: I realize I could create a class that has overloaded constructors and assignment operators and pass a variable of that class instead to the function.
Use sfinae
template<typename> struct restrict { };
template<> struct restrict<string> { typedef void type; };
template<> struct restrict<int> { typedef void type; };
template <typename T>
typename restrict<T>::type foo(T bar);
That foo will only be able to accept string or int for T. No hard compile time error occurs if you call foo(0.f), but rather if there is another function that accepts the argument, that one is taken instead.
You may create a "private" templatized function that is never exposed to the outside, and call it from your "safe" overloads.
By the way, usually there's the problem with exposing directly the templatized version: if the passed type isn't ok for it, a compilation error will be issued (unless you know your algorithm may expose subtle bugs with some data types).
You could probably work with templates specializations for the "restricted" types you want to allow. For all other types, you don't provide a template specialization so the generic "basic" template would be used. There you could use something like BOOST_STATIC_ASSERT to throw a compile error.
Here some pseudo-code to clarify my idea:
template <typename T>
void foo(T bar) {BOOST_STATIC_ASSERT(FALSE);}
template<> // specialized for double
void foo(double bar) {do_something_useful(bar);};
Perhaps a bit ugly solution, but functors could be an option:
class foo {
void operator()(double); // disable double type
public:
template<typename T>
void operator ()(T bar) {
// do something
}
};
void test() {
foo()(3); // compiles
foo()(2.3); // error
}
Edit: I inversed my solution
class foo {
template<typename T>
void operator ()(T bar, void* dummy) {
// do something
}
public:
// `int` is allowed
void operator ()(int i) {
operator ()(i, 0);
}
};
foo()(2.3); // unfortunately, compiles
foo()(3); // compiles
foo()("hi"); // error
To list an arbitrary selection of types I suppose you could use a typelist. E.g see the last part of my earlier answer.
The usage might be something like:
//TODO: enhance typelist declarations to hide the recursiveness
typedef t_list<std::string, t_list<int> > good_for_foo;
template <class T>
typename boost::enable_if<in_type_list<T, good_for_foo> >::type foo(T t);

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.