Use derived class for template constructor - c++

I have a class with a template constructor:
class TCons {
template <typename T> TCons(T t);
}
which is specialized in the implementation:
template <> TCons::TCons(int i) { doMyStuff(i); }
I also have a specialization for a base class:
template <> TCons::Tcons(TBase &t) { doMyStuff(t); }
But this doesn't seem to work when I try to initialize a TCons object using a derived object as a parameter.
class TDeriv: public TBase { };
TDeriv td;
TCons tc = td;
I can't use a pointer to resolve this issue (since everything is wrapped inside a macro). The problem arises during the link phase.
Is it just wrong, or am I missing something?

When we try to construct tc here:
TCons tc = td;
we have one choice of constructor:
template <typename T> TCons(T t);
When we perform template deduction, we deduce T = TDeriv. This does not match your TBase explicit specialization (nor the int one), so we stick with the primary template. You don't provide a definition for it, which is why you have a linker error.
If you want your TBase constructor to be called on all types that inherit from TBase, you'll have to disable the constructor template for those cases. We can do that with SFINAE:
template <typename T,
typename = std::enable_if_t<!std::is_base_of<TBase, T>::value>>
TCons(T );
while additionally making your other constructors non-template overloads:
TCons(int );
TCons(TBase& );
Only specialize when you need to - overloading is going to simpler.

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.

C++ - Deducing type from inherited constructor's arguments for class template

I have a class template that inherits the constructors of the base class template. (As for c++20) Is there a way to deduce the template arguments of the derived class from the constructor arguments of base?
If I specify the type explicitly, that works. Or if I reimplement the constructor and call the constructor of base, that also would work but is there a way to do without that?
template<typename T>
struct CTestBase
{
using Type = T;
CTestBase() = default;
CTestBase(T t){}
};
template<typename T>
struct CTestDer : public CTestBase<T>
{
using CTestBase<T>::CTestBase;
};
void test()
{
//CTestDer der(int{}); //ERROR
CTestDer<int> der(int{}); //OK
}
You can add a user-defined deduction guide:
#include <utility>
template<typename T>
struct CTestBase
{
using Type = T;
CTestBase() = default;
CTestBase(T t){}
};
template<typename T>
struct CTestDer : public CTestBase<T>
{
using CTestBase<T>::CTestBase;
};
template<typename T>
CTestDer(T &&t) -> CTestDer<std::remove_cvref_t<T>>;
void test()
{
CTestDer der(int{}); // OK now.
}
With a little bit more work it should be possible to:
Use a variadic template in the deduction guide
Have the deduction guide use decltype to construct, using its own deduction guide, the superclass
Use a specialization to figure out the superclass's template parameters
Use that to construct the subclass, to deduce it
This should handle anything. But this will be a lot of work. For this simple use case, and if it's not expected that the superclass will change much, this would be overkill.
but is there a way to do without that?
Yes, just add user-defined deduction guides for CTestDer:
template<typename T>
CTestDer(T) -> CTestDer<T>;
Demo

Passing template prototype as template argument - is it possible?

So first, apologies for terminology - I'm not sure if template prototype is the correct term. By this I mean :
template <class T, class X>
class TemplatePrototype
{
// code
};
I have a situation where I have a function that creates a template object based upon template arguments to that function.
template <class T, class X>
void doSomething()
{
TemplatePrototype<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
However, there are about 15 different versions of TemplatePrototype, which all have the same interface but different execution (TemplatePrototype is provided by another library). As a result, I have a lot of code that looks like this:
template <class T, class X>
void doSomethingWithOne()
{
TemplatePrototypeOne<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
template <class T, class X>
void doSomethingWithTwo()
{
TemplatePrototypeTwo<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
As a consequence of the architecture, I must know which TemplatePrototype I am going to use before I know the actual types T and X. I would like to see something like this:
template <class T, class X, class Prototype>
void doSomething()
{
Prototype<T, X> aPrototype;
aPrototype.doSomething();
}
But where I have specified part of the template arguments in advance - i.e I specify Prototype before I know T and X. Obviously, this is not possible in C++.
Equally, I cannot pass the Prototype as a template argument because it will still result in huge amounts of duplicate code.
Some important facts : I know the range of all possible inputs.
So I could theoretically use a macro to define each possible template specialisation and insert them into a container, which I would then use to access the specialisation I need. However, I am looking for a more 'elegant' solution - is it possible to pass template prototypes without specialising them as an argument to a template class, and then instantiate later when a function is called? Example:
template <class Prototype>
class Holder
{
template <class T, class X>
void doSomething()
{
Prototype<T, X> aPrototype;
aPrototype.doSomethingElse();
}
};
As far as I know this is impossible, but I was wondering if the SO community had some folks who know a solution?
EDIT:
So I have implemented this as my solution, thanks to the answers below!
#include <iostream>
template <typename T>
struct Foo
{
Foo() { aPtr = 0; }
T* aPtr;
};
template <template<typename> class C>
struct Bar
{
template <class T>
void doSomething()
{
C<T> aClass;
if (aClass.aPtr)
std::cout << "Hello world" << std::endl;
}
};
int main()
{
Bar<Foo> aFoo;
aFoo.doSomething<int>();
return 0;
}
This enables me to specify which TemplatePrototype I wish to use, before I can know the template parameters.
Yes, use a template template parameter, e.g.
template <typename T>
struct Foo
{
};
template <template<typename> class C>
struct Bar
{
};
then
Bar<Foo> b;
You're looking for template template parameters.
In the template parameter list, instead of just:
class TemplatePrototype
specify your prototype as a class template which itself has two template type parameters (without giving them a name here), like:
template<class,class> class TemplatePrototype
//^^^^^^^^^^^^^^^^^^^
This will result in a function like:
template <class T, class X,
template<class,class> class TemplatePrototype>
void doSomething()
{
TemplatePrototype<T, X> aTemplateTX;
aTemplateTX.doSomethingElse();
}
Invocation example:
doSomething<T, X, TemplatePrototypeOne>();
To become independent of the number of template parameters you pass to your "prototype" (here it was 2, namely T and X), you can use variadic templates (since C++11).
For this, first move the prototype template parameter to the first position:
template <template<class,class> class TemplatePrototype,
class T, class X>
Then, replace class T, class X with class ...Ts, which is a placeholder of an arbitrary number of type parameters. Also, in the template template parameter list, replace class,class with class.... And in the instantiation within the function implementation, replace <T, X> with <Ts...> to "expand" the parameter pack.
The result then looks like this:
template <template<class...> class TemplatePrototype,
class ... Ts>
void doSomething()
{
TemplatePrototype<Ts...> aTemplateTs;
aTemplateTs.doSomethingElse();
}
Live demo

Understanding (simple?) C++ Partial Template Specialization

Note: this seems to be a repost of a problem: C++ - Overload templated class method with a partial specilization of that method
I have boiled down a problem I am having with C++ template specialization down to a simple case.
It consists of a simple 2-parameter template class Thing, where I would like to specialize Thing<A,B>::doSomething() for B=int.
#include <cstdio>
// A 3-parameter template class.
template <class A, class B>
class Thing
{
public:
Thing(A a, B b) : a_(a), b_(b) {}
B doSomething();
private:
A a_;
B b_;
};
// The generic case works as expected.
template <class A, class B>
B Thing<A,B>::doSomething()
{
return b_;
}
// This specialization does not work!
template <class A>
int Thing<A,int>::doSomething()
{
return b_+1;
}
int main() {
// Setup our thing.
Thing<double,int> thing(1.0,2);
// This doesn't compile - but works with the generic case.
printf("Expecting 3, and getting %i\n", thing.doSomething());
// Clean up.
return 0;
}
Unfortunately, g++ exits with the error:
partial_specialization.cpp:30: error: invalid use of incomplete type ‘class Thing<A, int>’
partial_specialization.cpp:8: error: declaration of ‘class Thing<A, int>’
The clang++ compiler is a bit more verbose, but has the same problem:
partial_specialization.cpp:30:19: error: nested name specifier 'Thing<A, int>::' for declaration does not
refer into a class, class template or class template partial specialization
int Thing<A,int>::doSomething()
~~~~~~~~~~~~~~^
partial_specialization.cpp:32:12: error: use of undeclared identifier 'b_'
return b_+1;
^
2 errors generated.
I have read and understood that partial template specializations on functions aren't allowed - but I thought I was partially specializing over classes of Thing in this case.
Any ideas?
What I did: A workaround, as determined from the link provided by the accepted answer:
template< class T >
inline T foo( T const & v ) { return v; }
template<>
inline int foo( int const & v ) { return v+1; }
// The generic case works as expected.
template <class A, class B>
B Thing<A,B>::doSomething()
{
return foo(b_);
}
Partial specialization of a function template, whether it is member function template or stand-alone function template, is not allowed by the Standard:
template<typename T, typename U> void f() {} //okay - primary template
template<typename T> void f<T,int>() {} //error - partial specialization
template<> void f<unsigned char,int>() {} //okay - full specialization
But you can partially specialize the class template itself. You can do something like this:
template <class A>
class Thing<A,int> //partial specialization of the class template
{
//..
int doSomething();
};
template <class A>
int Thing<A,int>::doSomething() { /* do whatever you want to do here */ }
Note that when you partially specialize a class template, then the template parameter-list of member function (in its definition outside the class), must match the template parameter list of the class template partial specialization. That means, for the above partial specialization of the class template, you cannot define this:
template <class A>
int Thing<A,double>::doSomething(); //error
Its not allowed, because the template parameter-list in function definition didn't match the template parameter-list of the class template partial specialization. §14.5.4.3/1 from the Standard (2003) says,
The template parameter list of a member of a class template partial specialization shall match the template parameter list of the class template partial specialization.[...]
For more on this, read my answer here:
C++ - Overload templated class method with a partial specilization of that method
So what is the solution? Would you partially specialize your class along with all the repetitive work?
A simple solution would be work delegation, instead of partially specializing the class template. Write a stand-alone function template and specialize this as:
template <class B>
B doTheActualSomething(B & b) { return b; }
template <>
int doTheActualSomething<int>(int & b) { return b + 1; }
And then call this function template from doSomething() member function as:
template <class A, class B>
B Thing<A,B>::doSomething() { return doTheActualSomething<B>(b_); }
Since in your particular case, doTheActualSomething needs to know the value of only one member, namely b_, the above solution is fine, as you can pass the value to the function as argument whose type is the template type argument B, and specialization for int is possible being it full-specialization.
But imagine if it needs to access multiple members, type of each depends on the template type argument-list, then defining a stand-alone function template wouldn't solve the problem, because now there will be more than one type argument to the function template, and you cannot partially specialize the function for just, say, one type (as its not allowed).
So in this case you can define a class template instead, which defines a static non-template member function doTheActualSomething. Here is how:
template<typename A, typename B>
struct Worker
{
B doTheActualSomething(Thing<A,B> *thing)
{
return thing->b_;
}
};
//partial specialization of the class template itself, for B = int
template<typename A>
struct Worker<A,int>
{
int doTheActualSomething(Thing<A,int> *thing)
{
return thing->b_ + 1;
}
};
Notice that you can use thing pointer to access any member of the class. Of course, if it needs to access private members, then you've to make struct Worker a friend of Thing class template, as:
//forward class template declaration
template<typename T, typename U> struct Worker
template <class A, class B>
class Thing
{
template<typename T, typename U> friend struct Worker; //make it friend
//...
};
Now delegate the work to the friend as:
template <class A, class B>
B Thing<A,B>::doSomething()
{
return Worker<A,B>::doTheActualSomething(this); //delegate work
}
Two points to be noted here:
In this solution, doTheActualSomething is not a member function template. Its not enclosing class which is template. Hence we can partially specialize the class template anytime, to get the desired effect of the partial member function template specialization.
Since we pass this pointer as argument to the function, we can access any member of the class Thing<A,B>, even private members, as Worker<T,U> is also a friend.
Complete online demo : http://www.ideone.com/uEQ4S
Now there is still a chance of improvement. Now all instantiations of Worker class template are friends of all instantiation of Thing class template. So we can restrict this many-to-many friendship as:
template <class A, class B>
class Thing
{
friend struct Worker<A,B>; //make it friend
//...
};
Now only one instantiation of Worker class template is a friend of one instantiation of Thing class template. That is one-to-one friendship. That is, Worker<A,B> is a friend of Thing<A,B>. Worker<A,B> is NOT a friend of Thing<A,C>.
This change requires us to write the code in somewhat different order. See the complete demo, with all the ordering of class and function definitions and all:
http://www.ideone.com/6a1Ih
This is a very often found problem, and there is a surprisingly simple solution. I will show it in an artificial example, because it's more clearer than to use your code, and you will have to understand it to adapt it to your code
template<typename A, typename B>
struct TwoTypes { };
template<typename A, typename B>
struct X {
/* forwards ... */
void f() { fImpl(TwoTypes<A, B>()); }
/* special overload for <A, int> */
template<typename A1>
void fImpl(TwoTypes<A1, int>) {
/* ... */
}
/* generic */
template<typename A1, typename B1>
void fImpl(TwoTypes<A1, B1>) {
/* ... */
}
};
Explicitly specializing functions is never (almost never?) the right way. In my work as a programmer, I've never explicitly specialized a function template. Overloading and partial ordering is superior.

C++ - Overload templated class method with a partial specilization of that method

There are a few questions already similar to this already on stack overflow, but nothing that seemd to directly answer the question I have. I do apologise if I am reposting.
I'd like to overload a few methods of a templated class (with 2 template parameters) with a partial template specialisation of those methods. I haven't been able to figure out the correct syntax, and am starting to think that it's not possible. I thought I'd post here to see if I can get confirmation.
Example code to follow:
template <typename T, typename U>
class Test
{
public:
void Set( T t, U u );
T m_T;
U m_U;
};
// Fully templated method that should be used most of the time
template <typename T, typename U>
inline void Test<T,U>::Set( T t, U u )
{
m_T=t;
m_U=u;
}
// Partial specialisation that should only be used when U is a float.
// This generates compile errors
template <typename T>
inline void Test<T,float>::Set( T t, float u )
{
m_T=t;
m_U=u+0.5f;
}
int _tmain(int argc, _TCHAR* argv[])
{
Test<int, int> testOne;
int a = 1;
testOne.Set( a, a );
Test<int, float> testTwo;
float f = 1.f;
testTwo.Set( a, f );
}
I know that I could write a partial specialisation of the entire class, but that kinda sucks. Is something like this possible?
(I'm using VS2008)
Edit: Here is the compile error
error C2244: 'Test::Set' : unable to match function definition to an existing declaration
Thanks :)
You cannot partially specialize a member function without defining partial specialization of the class template itself. Note that partial specialization of a template is STILL a template, hence when the compiler sees Test<T, float>, it expects a partial specialization of the class template.
--
$14.5.4.3/1 from the C++ Standard (2003) says,
The template parameter list of a
member of a class template partial
specialization shall match the
template parameter list of the class
template partial specialization. The
template argument list of a member of
a class template partial
specialization shall match the
template argument list of the class
template partial specialization. A
class template specialization is a
distinct template. The members of the
class template partial specialization
are unrelated to the members of the
primary template. Class template
partial specialization members that
are used in a way that requires a
definition shall be defined; the
definitions of members of the primary
template are never used as definitions
for members of a class template
partial specialization. An explicit
specialization of a member of a class
template partial specialization is
declared in the same way as an
explicit specialization of the primary
template.
Then the Standard itself gives this example,
// primary template
template<class T, int I> struct A {
void f();
};
template<class T, int I> void A<T,I>::f() { }
// class template partial specialization
template<class T> struct A<T,2> {
void f();
void g();
void h();
};
// member of class template partial specialization
template<class T> void A<T,2>::g() { }
I hope the quotation from the Standard along with the example answers your question well.
The particular problem you're sketching is easy:
template< class T >
inline T foo( T const& v ) { return v; }
template<>
float foo( float const& v ) { return v+0.5; }
Then call foo from your Test::Set implementation.
If you want the full generality, then similarly use a helper class with static helper member functions, and partially specialize that helper class.
Cheers & hth.,
There's also another solution to the partial specialization problem, if you don't want to introduce additional functions, methods or classes to your code.
#include <type_traits>
template <typename T1, typename T2>
class C
{
void f(T1 t1);
}
template <typename T1, typename T2>
void C<T1, T2>::f(T1 t1)
{
if (std::is_same<T2, float>::value)
// Do sth
else
// Do sth
}