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

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

Related

Is this partial template specialization?

I am trying to understand type function in template metaprogramming trough some examples.
I have created one example that removes the reference from a type.
template <class T>
struct remove_reference
{ using type = T; };
template <class T>
struct remove_reference<T&>
{ using type = T; };
int main(){
typename remove_reference<int&>::type a;
}
My question is if this is implemented using partial template specialization of if we call it something else?
I feel it is partial because we have not defined it for a specific type but I also feel it isn't because we have just as many template arguments.
The naming may not be important to understanding type functions but I don't want to teach other people the wrong names if I explain it.
Yes, it is partial specialisation, because you have restricted to just things that match the pattern T&.
You don't need to have fewer template parameters, you can even have more. E.g.
template <typename Callable>
struct function_something { ... }; // Any functor type
template <typename Ret, typename Args...>
struct function_something<Ret(Args...)> { ... }; // Specialises free functions
template <typename Class, typename Ret, typename Args...>
struct function_something<Ret(Class::*)(Args...)> { ... }; // Specialises member functions

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.

Is there a standard generalization of void_t for other types?

In C++17, we have std::void_t, which makes SFINAE look a lot nicer:
template <typename T>
std::void_t<decltype(T::prop)> foo() { /* stuff */ }
The template function will exist only if T::prop exists.
If T::prop exists, the template function foo() would be equivalent to this:
template <typename T>
void foo() { /* stuff */ }
Otherwise, the code is equivalent to not declaring foo() at all.
Is there any generalization of std::void_t for other types in the standard library, such as the following:
template<typename T, typename...>
using generic_t = T;
so that the code below would be valid?
template <typename T>
std::generic_t<int, decltype(T::prop)> foo() { /* stuff */ }
which would be equivalent to
template <typename T>
int foo() { /* stuff */ }
if T::prop exists?
Why do you need such a generalization? void_t is a little special in that it helps you easily write type traits, because you can have a primary with some type defaulted to void and a specialization which uses void_t. For instance:
template <class T, class = void>
struct has_prop : std::false_type { };
template <class T>
struct has_prop<T, std::void_t<decltype(T::prop)>> : std::true_type { };
It's not that there's anything special about void, you just need some agreed upon type between the primary and the specialization.
void_t doesn't make much sense if you're just using it directly in SFINAE though. You could just stick the expression somewhere else:
template <typename T, class = decltype(T::prop)>
void foo() { /* stuff */ }
at which point the return type is totally separate from the condition you're checking anyway, so if you want int:
template <typename T, class = decltype(T::prop)>
int foo() { /* stuff */ }
It probably does not exist. It is not linked in the documentation and therefore I doubt its existence. But you can build such type on your own:
template <class type, class... sfinae_expressions>
using generic_t = type;

Partial instantiation of template template parameter

Suppose I build a class template with template parameter:
template<template<typename> class A> class B;
And now I want to make an instantiation, for example for A being functions taking int (e.g. for arguments like template<class T> void f(int)). Is there any way to do this?
No. Template template arguments can't be used with function template.
A template argument for a template template parameter must be an
id-expression which names a class template or a template alias.
As per the other answer, template template arguments cannot be used with function templates. You could however, simulate desired functionality by wrapping your function in a templated functor instead. The simplest would be an std::function. Here is a silly example to demonstrate this:
#include <iostream>
#include <functional>
template<template <class A> class T>
class B
{
public:
template<typename Arg>
void invoke(T<Arg> target, Arg arg)
{
target(arg);
}
};
template<typename T>
void f(T arg)
{
std::cout << arg << std::endl;
}
template<typename T>
using fWrapper = std::function<void(T)>;
int main()
{
B<fWrapper> b;
b.invoke<int>(fWrapper<int>(f<int>), 1);
return 0;
}
You cannot pass template functions around to other templates.
You can create template objects that act like template functions, such as:
struct my_wrapper {
template<class T>
static void invoke(int) {};
};
You can pass a type and expect that it have a static template function called invoke that takes a type.

Specialize a template with a template

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