Partial instantiation of template template parameter - c++

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.

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>

How to declare a variable whose type is the generics of another object?

Consider the following piece of C++ code:
int main(){
MyObject<int> obj;
foo(obj);
}
template <typename T>
void foo(T& objct){
...
}
In foo, the type of objct will be MyObject<int>.
I would like to create a variable in foo() whose type is the objct's generics, in this case, int.
Is there a way to do that? Thank you.
Edit
Unfortunately (I think) I can't rewrite the signature because the function foo() is called with different type of objects, for example
int main(){
MyObject<int> obj;
MyDifferentObject<int> obj2;
foo(obj);
foo(obj2);
}
What about defining foo() using a template-template parameter?
template <template <typename...> class C, typename T>
void foo (C<T> & objct)
{
/...
}
or also
template <template <typename...> class C, typename T, typename ... Ts>
void foo (C<T, Ts...> & objct)
{
/...
}
to be more flexible and accept also type with multiple template types parameters.
This way, if you call
MyObject<int> obj;
MyDifferentObject obj2;
foo(obj);
foo(obj2);
you have that C is MyObject in first case, MyDifferentObject in the second case and T is int in both cases.
This, obviously, works only if the argument of foo() are object of a template class with only template type parameters so, for example, doesn't works for std::array
std::vector<int> v;
std::array<int, 5u> a;
foo(v); // compile: only types parameters for std::vector
foo(a); // compilation error: a non-type template parameter for std::array
I would like to create a variable in foo() whose type is the objct's generics, in this case, int.
Is there a way to do that?
If you can change the function signature, then you can do this:
template <typename T>
void foo(MyObject<T>& objct){
T variable;
If that is not an option, for example if you want foo to allow other templates too (such as in your edited question), then you can define a type trait:
template<class T>
struct fancy_type_trait
{
};
template<class T>
struct fancy_type_trait<MyObject<T>>
{
using type = T;
};
template<class T>
struct fancy_type_trait<MyDifferentObject<T>>
{
using type = T;
};
template <typename T>
void foo(T& objct){
using V = typename fancy_type_trait<T>::type;
V variable;
You can write a trait that determines the first template parameter of any instantiation of a template with one template parameter:
#include <type_traits>
template <typename T>
struct MyObject {};
template <typename T>
struct MyOtherObject {};
template <typename T>
struct first_template_parameter;
template <template<typename> typename T,typename X>
struct first_template_parameter< T<X> > {
using type = X;
};
int main() {
static_assert(std::is_same< first_template_parameter<MyObject<int>>::type,
first_template_parameter<MyOtherObject<int>>::type>::value );
}
The trait first_template_parameter can take any instantiation of a template with a single parameter and tells you what that parameter is. first_template_parameter< MyObject<int> >::type is int. More generally first_template_parameter< SomeTemplate<T> >::type is T (given that SomeTemplate has one parameter).
This is a slight generalization of the trait used in this answer and if needed it could be generalized to also work for instantiations of tempaltes with more than one parameter.
In your function you would use it like this:
template <typename T>
void foo(T& objct){
typename first_template_parameter<T>::type x;
}

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

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.

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