Specialization template class with templated function - c++

I have some helper template with templated function. I'm using it for other policy-based templated class to cast or not to cast some value to specific type:
// use this when needed additional value cast
template <typename T>
struct AdditionalValueStaticCaster
{
template <typename U>
static T cast(U u)
{
return static_cast<T>(u);
}
};
// use this specialization when no needed to cast value
template <>
struct AdditionalValueStaticCaster<void>
{
template <typename U>
static U cast(U u)
{
return u;
}
};
Now I want to split these classes to declaration and implementation (.h and .hh files)
So I write declaration like this:
template <typename T>
struct AdditionalValueStaticCaster
{
template <typename U>
static T cast(U u);
};
template <>
struct AdditionalValueStaticCaster<void>
{
template <typename U>
static U cast(U u);
};
And now I want to write implementation. This is ok:
template <typename T>
template <typename U>
T AdditionalValueStaticCaster<T>::cast(U u)
{
return static_cast<T>(u);
}
But this causes error error: too many template-parameter-lists
template<>
template <typename U>
U AdditionalValueStaticCaster<void>::cast(U u)
{
return u;
}
If I delete line template<> all compiles ok, but I still have a question: is it right solution or I missed something?

If I delete line template<> all compiles ok, but I still has question: is it right solution or I missed something?
That's correct, you just need to delete that line. AdditionalValueStaticCaster<void> is a concrete type and you're just providing the definition of a member function template on that type. Hence:
template <typename U>
U AdditionalValueStaticCaster<void>::cast(U u)
{
return u;
}
No different than the member function template on any other class type:
template <typename U>
U SomeClass::cast(U u)
{
return u;
}

I don't think that you can define a template with in a template.
put all the template parameters in the first template line. like this.
template <typename T, typename U>
struct AdditionalValueStaticCaster
{
static T cast(U u)
{
return static_cast<T>(u);
}
};
specialized to an actual object like this:
AdditionalValueStaticCaster< My_T_Type, My_U_Type> MyNewCaster;
and used like this
My_T_Type My_T_Type_var;
My_U_Type My_U_Type_var;
My_T_Type_var = MyNewCaster.cast(My_U_Type_var);
Sorry I don't have a compiler to check this on, but syntax should be close.

Related

Function template partial specialization - are there any workaround?

I have the following function
enum class NodeCachingOptions
{
AddPath,
DontAddPath
};
template <typename T, NodeCachingOptions>
T* CreateSObject(const MPath& path)
Idea was to specialize function for different NodeCachingOptions.
Turned out it is impossible to use partial function template specialization, thus I tried a workaround:
template <typename T, NodeCachingOptions>
T* CreateSObject(const MPath& ob)
{
CreateSObject_Impl<class T, NodeCachingOptions> temp
return temp.call(ob);
}
template <typename T, NodeCachingOptions>
struct CreateSObject_Impl
{
T* call(const MPath& ob);
};
template <typename T>
struct CreateSObject_Impl<typename T, NodeCachingOptions::AddPath>
{
T* call(const MDagPath& ob)
{…}
}
template <typename T>
struct CreateSObject_Impl<typename T, NodeCachingOptions::DontAddPath>
{…}
However I'm getting compile error: ::NodeCachingOptions': illegal type for non-type template parameter '__formal'
What am I doing wrong and is there a better way to solve this problem?
I took idea of struct impl from here: Partial template specialization of free functions - best practices
Your syntax is all wrong. Make it
template <typename T, NodeCachingOptions opt>
T* CreateSObject(const MPath& ob)
{
CreateSObject_Impl<T, opt> temp;
return temp.call(ob);
}
You pass the value of type NodeCachingOptions as the second template paramter of CreateSObject_Impl, not the type itself.
You may want to make call a static member of CreateSObject_Impl, and write return CreateSObject_Impl<T, opt>::call(ob);

function implementation with enable_if outside of class definition

So basically, I have a very basic generic class for now, currently testing the type_traits header. I am currently trying to make a function to work with certain types i.e arithmetic ones for now.
#include <type_traits>
template <typename T> class Test {
public:
template <typename U = T>
typename std::enable_if<std::is_arithmetic<U>::value>::type print();
};
The function works perfectly and for arithmetic types only.
But I like to keep my classes tidy and only have them have prototypes, while the function implementations are outside of the class.
With standard templates i.e
void test();
template <typename T> void Test<T>::test() {}
It is simple and I know how to, but I have no clue how to declare the implementation outside of the class with "std::enable_if" and every attempt I have made, during compilation says that that the prototype does not match any in the class.
I have managed to find a similar question here but the class there is standard and not generic.
PS. I am using MinGW-w64 with -std=c++17
You need one set of template parameters for the class template and one separate set of template parameters for the member function template. You need to repeat the entire complicated return type, since it's part of the function template signature. And note you cannot repeat the default argument =T, or the compiler will think you're trying to define it twice (without checking whether or not the new definition is identical).
template <typename T> template <typename U>
typename std::enable_if<std::is_arithmetic<U>::value>::type
Test<T>::print()
{
// Implementation here.
}
By the way, you're using the "long way" of writing the type, as was needed in C++11. But C++14 introduced a std::enable_if_t shortcut, and C++17 introduced a std::is_arithmetic_v shortcut. So if you're using C++17, you can also write the type
typename std::enable_if<std::is_arithmetic<U>::value>::type
as just
std::enable_if_t<std::is_arithmetic_v<U>>
If you put the enable_if in the default template parameter, which is imo nicer anyway, the out-of-class definition becomes a bit easier:
template<typename T>
struct Test
{
template <typename S = T
, typename = typename std::enable_if<std::is_arithmetic<S>::value>::type >
void print();
};
template<typename T>
template<typename S, typename>
void Test<T>::print()
{
//some code
}
You can try with
template <typename T>
template <typename U>
std::enable_if_t<std::is_arithmetic<U>::value> Test<T>::print()
{ /* do something */ }
The following is a full working example
#include <iostream>
#include <type_traits>
template <typename T> class Test
{
public:
template <typename U = T>
std::enable_if_t<std::is_arithmetic<U>::value> print();
};
template <typename T>
template <typename U>
std::enable_if_t<std::is_arithmetic<U>::value> Test<T>::print()
{ std::cout << "test!" << std::endl; }
int main ()
{
Test<int> ti;
Test<void> tv;
ti.print(); // compile
//tv.print(); // compilation error
}
Off Topic 1
Observe that your solution can be hijacked in this way
Test<void>{}.print<int>();
To avoid this problem you could impose that T is equal to U,
template <typename T> class Test
{
public:
template <typename U = T>
std::enable_if_t< std::is_arithmetic<U>::value
&& std::is_same<T, U>::value> print()
{ }
};
Off Topic 2
As you can see, you have to repeat the SFINAE part (std::enable_if_t, std::is_arithmetic and std::is_same).
Taking in count that you have to repeat the implementation in an header, I don't think (IMHO) that to write the implementation of template classes outside the body of the class is a great idea.
Since you haven't posted what you attempted I can't tell you where you went wrong. But this is how you would implement the member function outside the class definition (although it still needs to be implemented in the header, so I don't think this is worth the trouble)
template <typename T> class Test {
public:
template <typename U = T>
typename std::enable_if<std::is_arithmetic<U>::value>::type print();
};
template <typename T> // class template parameter
template <typename U> // function template parameter
inline typename std::enable_if<std::is_arithmetic<U>::value>::type Test<T>::print()
{
}
Live demo
template<typename T>
struct test
{
template<typename U = T>
typename std::enable_if<std::is_arithmetic<U>::value>::type print();
};
template<typename T> template<typename U>
typename std::enable_if<std::is_arithmetic<U>::value>::type test<T>::print()
{
}
void foo()
{
test<int> t;
t.print();
test<void*> u;
u.print();
}
If you need an extra template parameter U, as the other answers explained the right syntax is
template<typename T>
struct test
{
template<typename U>
... a_method(...);
};
template<typename T>
template<typename U>
... test<T>::a_method(...)
{
...
}
However in your peculiar case, if you only need to check some properties of the T type this is really an extra complication. Introduction of the U type is "artificial" and is only here because of the SFINAE
IMHO, it is much more elegant and simpler to use if constexpr
#include <iostream>
#include <type_traits>
template <typename T>
class Test
{
public:
void print();
};
template <typename T>
void Test<T>::print()
{
if constexpr (std::is_arithmetic_v<T>)
{
std::cout << "\nOk T is arithmetic";
// ... your implementation here ...
}
else
{
// throw an exception or do what ever you want,
// here a compile-time error
static_assert(!std::is_same_v<T, T>, "not implemented yet...");
}
}
main()
{
Test<int> t;
t.print();
Test<void> t2;
// t2.print(); <- will generate a compile time error
}

How do two structures with same name and with different Template arguments work

Why does only first implementation work and not the other implementations specified below,
Can someone explain the way this template structure work and why others do not.
Template structures that work
template <typename T, typename U>
struct is_same
{
static const bool value = false;
};
template <typename T>
struct is_same<T, T>
{
static const bool value = true;
};
Template structures that do not work
template <typename T, typename U>
struct is_same<T, U>
{
static const bool value = false;
};
template <typename T>
struct is_same<T, T>
{
static const bool value = true;
};
One more that does not work
template <typename T, typename U>
struct is_same<T,U>
{
static const bool value = false;
};
template <typename T>
struct is_same
{
static const bool value = true;
};
And the Main Function
template <class A, class B>
bool IsSameClass() {
return is_same<A, B>::value;
}
int main()
{
bool ret = IsSameClass<P,C>();
}
You always start with a template definition:
template <class T, class U>
class is_same { ... };
Or, as Jarod42 reminded me, with a declaration:
template <class T, class U> class is_same;
Once there's a template, you can define a partial specialization by refining one or more of the template arguments, as in your example:
template <class T>
class is_same<T, T> { ...};
The specialization still takes two arguments, just like the original template, but they're the same type, so there's only one type name in the template <...> part of the definition.
In use, is_same<int, double> would match the template definition; is_same<int, int> would match the partial specialization.
You can also specify a full specialization. Not that you'd want to here, but following on with this example:
template <>
class is_same<void, void> { ... };
This would match, obviously, is_same<void, void>.
The reason that the other two attempts don't work is that neither of them has a template definition, only things that look like specializations. Without a definition there's nothing to specialize.
Note that this is a bit of an oversimplification. It's intended to address "why don't these things work", not "how can I specialize a template".
The syntax
template <typename T, typename U>
struct is_same<T, U>
{
static const bool value = false;
};
is used to create a specialization of a class template. In order to do that, you have to first declare the template or create its generic definition first.
template <typename T, typename U> struct is_same;
or
template <typename T, typename U>
struct is_same
{
static const bool value = false;
};
Even if you did that,
template <typename T, typename U>
struct is_same<T, U>
{
static const bool value = false;
};
is not a valid specialization since there is no way to decide which template to use when instantiated with is_same<int, float>.
Templates cannot be overloaded by using:
template <typename T, typename U>
struct is_same
{
static const bool value = false;
};
template <typename T>
struct is_same
{
static const bool value = true;
};
The language simply does not allow that.

Template friend function of template class that introduces a new template parameter

Thanks to Daniel Frey's answer to this post, I know how to declare a template friend function to a template class with the same template parameters. Unfortunately, the syntax for declaring a friend function with additional template parameters still escapes me. I would like to achieve something like this:
template <typename T>
class Obj;
template <typename T>
Obj<T> make_obj(T t);
template <typename T, typename RetVal>
RetVal ret_obj(T t);
template <typename T>
class Obj {
private:
T & t;
Obj (T & t) : t(t) { }
Obj() = delete;
friend Obj make_obj<T>(T t);
template <typename RetVal>
friend RetVal ret_obj<T, RetVal>(T t);
};
template <typename T>
Obj<T> make_obj(T t) {
return Obj<T>(t);
}
template <typename T, typename RetVal>
RetVal ret_obj(T t) {
return RetVal(make_obj(t).t);
}
I know that the same question has already been asked in this post, but the accepted answer there does not seem to be what I want: changing the parameter name to T2 makes the function a friend of all specializations of the object, while I want to keep T the same as in the class.
It is impossible to let friend declarations refer to partial specializations - either they refer to a specific specialization or to the primary template. Moreover, function templates cannot be partially specialized anyway.
What is not possible with function templates is often doable using class templates though:
template <typename T>
struct ret_obj_helper {
// Here goes the original definition of ret_obj - the important difference
// is the location of the template parameter T, which is the one
// fixed by the friend declaration below
template <typename RetVal>
RetVal ret_obj(T t) {return RetVal(make_obj(t).t);}
};
// I guess RetVal, having to be explicitly specified, better goes first (?)
template <typename RetVal, typename T>
RetVal ret_obj(T&& t)
{
// Overcomplicated for the sake of perfect forwarding
return ret_obj_helper<typename std::remove_reference<T>::type>{}.
template ret_obj<RetVal>(std::forward<T>(t));
}
template <typename T>
class Obj {
private:
T t;
Obj (T t) : t(t) { }
Obj() = delete;
friend Obj make_obj<T>(T t);
// Make all specializations of the member function template
// of ret_obj_helper<T> a friend, regardless of the return type
template <typename RetVal>
friend RetVal ret_obj_helper<T>::ret_obj(T t);
};
Demo.

How to create template for this function?

For structs
<template typename T>
struct Foo
{
...
}
<template typename T>
struct Boo
{
...
}
I want to create function that i will call like
DoSomething<Boo<int>>(x);
DoSomething<Foo<float>>(x);
I tried something like this
<template typename T>
<template typename U>
void DoSomething(T<U>& x)
but it doesn't compile. How do I make template for this kind of function?
Thanks
just do:
template <typename T>
struct Foo
{
};
template <typename T>
struct Boo
{
};
template <typename T>
void DoSomething(T& x) // One parameter is enough, compiler will deduce types automatically
{
}
Boo<int> x;
Foo<float> y;
DoSomething(x); // compiler will generate void DoSomething(Boo<int>& x)
DoSomething(y); // compiler will generate void DoSomething(Foo<float>& x)
Your template declaration is wrong,
<template typename T> // invalid syntax
should be:
template <typename T>
You need to use template template parameter if you want to specify both types:
template <template<typename> class T, typename U>
void DoSomething(T<U>& x)
But depending on what you want to achieve, if you don't need to have both types in your function, simply using a single template parameter should work:
template <typename Y>
void DoSomething(T& x)
<template typename T>
void DoSomething(T& x)
{
// do something
}
You have two choices. For the sake of the examples, consider your Foo template struct and this declaration:
Foo<double> v;
Your first choice is
template <typename T>
void DoSomething1(T& x) { /* ... */ }
// ...
DoSomething1(v);
I strongly believe this is what you need.
However, it might not be the case. Perhaps, you really need to call the function on a type of the form T<U> where T is a template class and U is a type. For instance you might want to instantiate T with an int (that is, create T<int> y;) inside the function's body. Then, your second choice is
template <template <typename> class T, typename U>
void DoSomething2(T<U>& x) { T<int> y; /* ... */ }
// ...
DoSomething2(v);
Unfortunately, this might not yet be enough! If you try,
std::vector<double> w;
// ...
DoSomething2(w);
The last line fails to compile. The reason is that std::vector is a template class that take two type parameters and DoSomething2 expects a template class that takes just one. (Of course one can instantiate std::vector with just one argument because the second one has a default value.) The solution is using a C++11 variadic template template parameter:
template <template <typename, typename...> class T, typename U>
void DoSomething3(T<U>&) { T<int> y; /* ... */ }
// ...
DoSomething3(v);
DoSomething3(w);