Specialize a template with a template - c++

I have a (free) function template that looks like this
template <typename T>
T get();
I now want to specialize this function for a class, which itself is a template. But my compiler doesn't want to compile it, and I'm asking now if that is even possible and how I could achieve it. Just for the idea, the code could look as follows: (Doesn't compile)
template <>
template <typename T>
foo_type<T> get<foo_type<T>>()

What you're doing is called partial specialization of function template. But partial specialization of function template is not allowed. Overloading of function template is allowed, but in this case, it is not possible either, as the function has only return type, and overloading on return type is not allowed.
So the solution is this:
namespace details
{
template <typename T>
struct worker
{
static T get();
};
template <typename T> //partial specialization of class is allowed
struct worker<foo<T>>
{
static foo<T> get();
};
}
template <typename T>
T get()
{
return details::worker<T>::get();
}
You could also use overloads if you define them to take one argument so as to make overload valid:
namespace details
{
template <typename T>
static T get(T*);
template <typename T>
static foo<T> get(foo<T>*); //now the overload is valid
}
template <typename T>
T get()
{
return details::get<T>(static_cast<T*>(0));
}
Note that the argument static_cast<T*>(0) is used to help the compiler to select the correct overload. If T is other than foo<U>, then the first overload will be selected as the type of the argument passed to it will be T* as opposed to foo<U>*. If T is foo<U>, then the second overload will be selected by the compiler because it is more specialized, and can accept the argument passed to it which is foo<U>* in this case.

As Nawaz said, the standard just doesn't allow you to do that. You could however extract the implementation into the static method of a class and partially specialize that class.
template<class T>
struct get_impl{
static T get(){ ... }
};
template<class T>
struct get_impl<foo_type<T> >{
static foo_type<T> get(){ ... }
};
template<class T>
T get(){ return get_impl<T>::get(); }

Related

Specialize template function to return vector

Let's say I have a reader class over a file:
class Reader {
public:
template <class T>
T Read();
};
Its only function is the Read function that reads any arithmetic type (static_assert(std::is_arithmetic_v<T>)) from a file. Now I want to create a specialization of that function, which reads a vector from the file. How would I go about doing that with templates? Something like the following doesn't work:
template <class T>
std::vector<T> Read<std::vector<T>>();
error: function template partial specialization is not allowed
std::vector<U> Read<std::vector<U>>();
^ ~~~~~~~~~~~~~~~~
You can't partially specialize functions. You can overload them though, but the way of doing it is not obvious, since your function doesn't take any parameters.
First, you need a way to check if a type is a std::vector<??>:
template <typename T> struct IsVector : std::false_type {};
template <typename ...P> struct IsVector<std::vector<P...>> : std::true_type {};
Then you can plug it into requires:
template <typename T>
T Read()
{
// Generic overload
}
template <typename T> requires IsVector<T>::value
T Read()
{
// Vector overload
}
Alternatively, you could have a single function, with if constexpr (IsVector<T>::value) inside.
A way to implement what you want is to delegate the logic of your member function to a couple of private member functions:
#include <cstdio>
#include <vector>
class BinaryReader {
public:
template <class T>
T Read() {
T t{};
this->ReadImpl(t);
return t;
}
private:
template <class T>
void ReadImpl(T& t) {
static_assert(std::is_arithmetic_v<T>);
std::puts("T");
t = T{}; // implement your logic here
}
template <class T>
void ReadImpl(std::vector<T>& t) {
std::puts("std::vector<T>");
t = std::vector<T>{}; // implement your logic here
}
};
int main() {
BinaryReader br;
br.Read<int>();
br.Read<std::vector<int>>();
}
This doesn't require you to introduce new type traits to check if your type is a std::vector<>. However, it requires your return types to be default constructible.
Output:
T
std::vector<T>

Specializing with two template arguments for an argument (C++ template)

I have no idea how to describe this question properly, but basically what I want to know is something like this can be compiled without a problem:
// prototype
template <class T>
void pretty_function(T arg);
// specialization
template <class U, class V>
void pretty_function<U<V>>(T arg);
So I want to specialize the type T with the type U< V >, where the type U requires a template argument V. I think I can easily test this on my local workstation, but I just leave it here for the future reference.
It sounds like you want to declare a specialization of pretty_function that would accept only types of the form U<V> where U can be any class template and V can be any type. This would be a partial specialization since the template argument T is not fully specified. C++ does not support partial specialization of function templates. The usual workaround is to dispatch to a helper class template that can be partially specialized:
namespace detail {
template <class T>
struct pretty_function_helper {
static void doit(T arg) { /* implementation */ }
};
// partial specialization
template <template <class> class U, class V>
struct pretty_function_helper<U<V>> {
static void doit(U<V> arg) { /* implementation */ }
};
}
template <class T> void pretty_function(T arg) {
detail::pretty_function_helper<T>::doit(arg);
}

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

Specializing templated function for a templated type?

I've got a function:
// declaration of random, specialize this to provide random instances of types
template <typename T> T random() {
static_assert(
std::is_void<T>::value && false, "random() not implemented for type"
);
}
I'd like to specialize it for another type, _point1d that's also templated:
template <typename T>
struct _point1d {
_point1d(T x) : x(x) {}
T x;
};
I tried this:
template <typename T>
_point1d<T> random<_point1d<T>>() { return _point1d<T>(random<T>()); }
But I get:
error: non-type partial specialization ‘random<_point1d<T> >’ is not allowed
With gcc. Is this possible?
You cannot specialize function templates partially.
The standard solution is to use an intermediate helper class template:
template <typename> struct Aux;
template <typename U> struct Aux<_point1d<U>>
{
static _point1d<U> f() { /* ... */ }
};
template <typename T> T random() { return Aux<T>::f(); }
// ^^^^^^^^^^^^^^^^^^^
That way you only have one single function template, and all the details of selecting the right specialization are done inside the class template, which you can freely specialize partially or explicitly as you choose.

How to check if template type is of another template type?

Suppose I have a template class with int parameter:
template <int Param>
class myclass
{
// ...
}
And I want to implement, for example, a cast function from one int-parametrized to another:
template <int Param, class T>
myclass<Param> myclass_cast(const T& other)
{
// ... some logic
}
How can I statically determine that T is a templated class myclass<N>? (I can use C++14).
Instead of having a template parameter of T, you can deduce the parameter of the myclass specialization you pass in:
template <int Param, int Other>
myclass<Param> myclass_cast (const myclass<Other>& other)
{
}