Suppose we have some converting routine class. If we can convert from T class to U, we automatically can convert vise versa.
I represent it with a template class and some specializations:
template <typename T, typename U>
class Convert;
template <>
class Convert<A,B> {
static int param() { return 42; }
}
template <>
class Convert<B,A> {
static int param() { return -Convert<A,B>::param(); }
}
This works good, but when we need to add new type for routine, we must add 2 specializiations.
Can we reduce that number to 1 by defining some general reverse template class like this:
template <typename T, typename U>
class Convert {
static int param() { return -Convert<U,T>::param(); }
}
which could be work if we already have Convert specialization?
Thanks in advance.
Here is the suggestion in my comment elaborated:
#include<iostream>
#include<type_traits>
struct A{};
struct B{};
struct C{};
template <typename ... Args>
struct Convert;
template <typename T>
struct Convert<T,T> {
static int param() { return 0; }
};
template <typename T, typename U>
struct Convert<T,U> {
static decltype(-Convert<U,T>::param()) param() { return -Convert<U,T>::param(); }
};
template <>
struct Convert<A,B> {
static int param() { return 42; }
};
template <>
struct Convert<A,C> {
static int param() { return 43; }
};
template <>
struct Convert<B,C> {
static int param() { return 44; }
};
int main()
{
std::cout<<Convert<A,B>::param()<<std::endl;
std::cout<<Convert<B,A>::param()<<std::endl;
std::cout<<Convert<A,C>::param()<<std::endl;
std::cout<<Convert<C,A>::param()<<std::endl;
std::cout<<Convert<B,C>::param()<<std::endl;
std::cout<<Convert<C,B>::param()<<std::endl;
Convert<int,double>::param();
}
The idea is to once give a general declaration, and then specify first the case where the template arguments are equal (that should give zero) as well as the case where they are different, in which the converted parameter is returned.
Next, for n classes, you need to give the specializations for all the n*(n-1)/2 Convert classes. (in case it is needed, this could further be simplified by derivation, for example).
Related
Let's say, we need a function template which should return an integer depending on a type:
template<typename T>
int get_type();
Further, we do specialize it with couple of types:
template<>
int get_type<int>()
{
return TYPE_INT;
}
// And so on for other types...
And this works well, but not for array types. I can do the following:
template<>
int get_type<char[]>()
{
return TYPE_STRING;
}
and compiler "agrees" with this, but linker does not. Because the type char[] differs against, for example, the char[5].
Is there any way to implement this function template without function parameters? I.e., I know that we can do something like this:
template<typename T>
int get_type(const T&);
But, actually the function parameter is not needed (used) here.
EDIT:
I use the C++ 11.
You cannot partial specialize template functions (but you can for template classes)
Another approach is tag dispatching with overloads, instead of specialization:
template <typename> struct Tag{};
constexpr int get_type(Tag<int>) { return TYPE_INT; }
template <std::size_t N>
constexpr int get_type(Tag<char[N]>) { return TYPE_STRING; }
template <typename T>
constexpr int get_type() { return get_type(Tag<T>{}); }
You need a partial specialisation to account for variable array lengths, and C++ does not allow partially specialised function templates. The canonical solution is to (partially) specialise a class template with a (static) member (function), and dispatch to that from within your unspecialised function template:
namespace detail {
template <typename T>
struct get_type;
template <>
struct get_type<int> {
static constexpr int value = TYPE_INT;
};
template <>
struct get_type<char> {
static constexpr int value = TYPE_CHAR;
};
template <typename T, std::size_t N>
struct get_type<T[N]> {
static constexpr int value = get_type<T>::value | TYPE_ARRAY;
};
template <std::size_t N>
struct get_type<char[N]> {
static constexpr int value = TYPE_STRING;
};
} // namespace detail
template<typename T>
constexpr int get_type() {
return detail::get_type<T>::value;
}
You can't partially specialize function for array with size. But you can do it with class.
template<typename T>
class type
{
static int get_type();
};
template<>
struct type<int>
{
static int get_type() { return 1; }
};
template<size_t SZ>
struct type<char[SZ]>
{
static int get_type() { return 2; }
};
template<typename T>
int get_type() { return type<T>::get_type(); }
int main()
{
std::cout << get_type<char[3]>() << std::endl;
return 0;
}
example
Konrad already described the best approach in my opinion.
Here is another approach with overloads and specialization powered by SFINAE
// overload 1, for non-array types
template<typename T>
std::enable_if_t<!std::is_array_v<T>, int> get_type();
// specialization of overload 1 for int
template <>
auto get_type<int>() -> int {
return 1;
}
// overload 2, for array types
template <typename T>
auto get_type() -> std::enable_if_t<std::is_array_v<T>, int> {
return 3;
}
Suppose, I have a code:
template <typename T>
class C {
public:
T f() { return m_result; }
void todo() { m_result = doit<T>(); }
private:
T m_result;
};
If T is void, I want to return void and have no m_result at all.
But, the compiler does not allow instantiate a void type.
One of decision is to create a specialization.
template <> class C<void> { /* ... */ }
But I don't what to support the almost identical code.
How can I don't instantiate m_result?
I can use C++17. Thanks!
You could place the data in a base class, then use if constexpr:
template<class T>
struct C_data{
T m_result;
};
template<>
struct C_data<void>{
};
template<class T>
class C: C_data<T>
{
static constexpr auto is_void = std::is_same_v<T,void>;
public:
auto f(){
if constexpr(is_void)
return this->m_result;
else
return;
}
void todo(){
if constexpr(is_void)
this->m_result = doit<T>();
else
doit<T>();
}
};
But it can be argued that a the specialization of the class C is cleaner since all member of a template class should depend on all the template parameter (otherwise you should split your class in order to avoid code bloat).
So I would prefer to fully specialize C, and make part of the class C that are independent of T, a base class of C:
class C_base{
//any thing that is independent of T;
};
template<class T>
class C: public C_base{
//any thing that depend on T
};
template<>
class C<void>: public C_base{
//any thing that depend on T;
};
You could also specialize member funtion by member function, but I find it less clean.
You will find this last code structure in almost all headers of standard library implementations.
This works for me:
#include <type_traits>
template <typename T> T doit() { return T{}; }
template <typename T> struct result_policy { T m_result; };
template <> struct result_policy<void> { };
template <typename T>
class C : private result_policy<T> {
public:
T f(){
if constexpr (!std::is_void_v<T>)
return result_policy<T>::m_result;
}
void todo() {
if constexpr(!std::is_void_v<T>)
result_policy<T>::m_result = doit<T>();
}
};
int main() {
C<int> ci;
ci.todo();
int i = ci.f();
C<void> cv;
cv.todo();
cv.f();
}
I used if constexpr from C++17 to work with m_result and stored m_result into policy struct only for non-void types due to partial template specialization.
If you can use C++17, then try with if constexpr, std::is_same_v<> and std::conditional_t<>:
#include <type_traits>
// auxiliary variable template for checking against void type in a more readable way
template<typename T>
constexpr bool is_void_v = std::is_same_v<T, void>;
// auxiliary alias template for determining the type of the data member
// in order to prevent the compiler from creating member of type "void"
// so if T = void --> data member type as "int"
template<typename T>
using member_type_t = std::conditional_t<!is_void_v<T>, T, int>;
template <typename T>
class C{
public:
T f(){ return (T)m_result; } // no problem if T = void
void todo() {
if constexpr(!is_void_v<T>)
m_result = doit<T>();
else
doit<T>();
}
private:
member_type_t<T> m_result;
};
Actually, as of C++17 there is already a std::is_void_v<> variable template with type_traits.
By using template template parameters one can pass to a class a templated class without specifying types on its parameters. I was wondering is there a way to pass into a template template parameter a templated signature of a function to be able to specialize which variant of the function is to be considered forward.
To be clear - I know I cannot do that:
template <class T>
void foo() { /*...*/ }
template <template <class...> class FooType>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo)> f;
}
But somehow I would like to be able to pass templated signature of function to Foo. Is it even possible?
I couldn't believe that this is not possible so I searched a bit and found a way to do exactly what I wanted. I used templated using with a syntax:
template <template<class... Args> class FooType>
struct Foo {
FooType<int> ft;
};
template <class Res, class... Args>
using FooSignature = Res(*)(Args...);
int foo() {
return 1;
}
int main() {
Foo<FooSignature> f;
f.ft = foo;
}
This however still leaves the question how can this be possible since the standard states something opposite.
In the example below one has a template template parameter that accepts the preferred signature for the function.
Because of the specialization and the lack of a body for the template class, only types for callables are accepted.
It is a generalization of what the OP actually asked:
#include<cassert>
template<typename F>
struct S;
template<typename R, typename... Args>
struct S<R(Args...)> {
using type = R(*)(Args...);
};
template<template<typename> class F>
struct T {
typename F<void(int)>::type ft;
typename F<double(double, double)>::type gt;
};
void f(int) { }
double g(double x, double y) { return x+y; }
int main() {
T<S> t;
t.ft = f;
t.gt = g;
t.ft(42);
auto v = t.gt(1., 1.);
assert(v == 2.);
}
As can be seen in this answer
Template of function pointer is illegal in C++
The C++ Standard says in $14/1,
A template defines a family of classes or functions.
Further quoting from the linked answer:
Please note that it does NOT say "A template defines a family of classes, functions or function pointers"
However, you can pass concrete function pointers, and specialise on their signature:
#include <iostream>
template <class T>
void foo(T) { }
template <typename>
struct Foo;
template<typename T>
struct Foo<void(T)>
{
void cb() { std::cout << "T\n"; }
};
template<>
struct Foo<void(int)>
{
void cb() { std::cout << "int\n"; }
};
template<>
struct Foo<void(double)>
{
void cb() { std::cout << "double\n"; }
};
int main()
{
Foo<decltype(foo<int >)>().cb(); // outputs 'int'
Foo<decltype(foo<double>)>().cb(); // outputs 'double'
Foo<decltype(foo<char >)>().cb(); // outputs 'T'
return 0;
}
template of template is still a template.
template <class T>
void foo() { /*...*/ }
template <typename T>
struct Foo { /*...*/ };
int main() {
Foo<decltype(foo<int>)> f;
}
You cannot pass a function template as an argument. What you can do is wrap a function template in a generate lambda taking a tag parameter:
template <class T> struct tag_t { using type = T; };
template <class T>
void foo() { ... }
template <class F>
void call_func_with(F f) {
f(tag_t<int>{} );
f(tag_t<double>{} );
}
call_with_func([](auto tag) { foo<decltype(tag)::type>(); } );
Here, f(tag_t<X>{} ) ends up calling foo<X>(), as desired.
I have a .h file with all my templates in it and a .cpp file with my main.
Part of .h templates:
template<int N, int P>
struct BOUND {
static inline int eval(int v) {
//...
return 1;
};
};
template<class K>
struct VAL_x {
static inline int eval(int v) {
//...
return 1;
};
};
template<int L, class K>
struct LIT {
static inline int eval(int v) {
//...
return 1;
};
};
template<class A, class B, class K>
struct ADD {
static inline int comp_b(int v){
// HERE check if class A is LIT or VAL_x
//...
return 2;
};
};
Here is how I call in my main() this template:
int main() {
typedef ADD<VAL_x<BOUND<2,3> >, LIT<2, BOUND<2,3> >, BOUND<2,3> > FORM;
FORM exec_form;
int y = 2;
int bounds = exec_form.comp_b(y);
return 0;
}
How can I know in ADD::comp() function of my struct, if an argument that was passed is instance of a specific class (e.g. LIT<> )? Those arguments can be passed in any order (e.g all arguments could be LIT, or only the second one)
NOTE: there are also other structs apart from VAL_x , LIT, BOUND and ADD.
Option #1
Introduce a separate trait for each class template of interest (C++03 doesn't help here much).
template <bool B> struct bool_constant { static const bool value = B; };
template <bool B> const bool bool_constant<B>::value;
template <typename T> struct is_LIT : bool_constant<false> {};
template <int L, int M> struct is_LIT<LIT<L, M> > : bool_constant<true> {};
template <typename T> struct is_VAL_x : bool_constant<false> {};
template <int K> struct is_VAL_x<VAL_x<K> > : bool_constant<true> {};
template <class A, class B>
struct ADD
{
static inline int comp_b(int v)
{
if (is_LIT<A>::value && is_VAL_x<B>::value)
{
}
return 2;
}
};
DEMO
Option #2
Use a generic custom trait, whose specialization detects if the type passed is an instantiation of the specified template-template parameter (it is if the specialization matches, i.e., T is an instantiation of class template X):
template <template <int> class X, typename T>
struct is_template { static const bool value = false; };
template <template <int> class X, int N>
struct is_template<X, X<N> > { static const bool value = true; };
template <typename A, typename B>
struct ADD
{
static inline int comp_b(int v)
{
if (is_template<VAL_x, A>::value && is_template<LIT, B>::value)
{
}
return 2;
}
};
DEMO 2
Option #3
Use tag-dispatching, possibly add overloads for other class templates that return true/false, making it similar to Option #1. This solution also relies on overload resolution, that prefers more specialized function templates over those less constrained/generic.
template <typename T> struct tag {};
template <typename A, typename B>
struct ADD
{
static inline int comp_b(int v)
{
return comp_b(v, tag<A>(), tag<B>());
}
template <int M, int N>
static inline int comp_b(int v, tag<LIT<M> >, tag<VAL_x<N> >)
{
return 1;
}
template <typename T, typename U>
static inline int comp_b(int v, tag<T>, tag<U>)
{
return 2;
}
};
DEMO 3
You could do it like this:
#include <typeinfo>
...
template<class A, class B>
struct ADD {
static inline int comp_b(int v){
// HERE check if class A is LIT or VAL_x
std::cout << ( typeid(A)==typeid(VAL_x) ) << '\n';
return 2;
};
};
where I am using std::type_info, which will print 1, for true evaluation.
Or, with c++11, you could do:
#include <type_traits>
...
if (std::is_same<A, VAL_x>::value)
std::cout << "they are same!\n";
However, you could overload a function or such. Make sure you read this: How do I check my template class is of a specific classtype? and this How to check for the type of a template parameter?
I want to specialize a class template with the following function:
template <typename T>
class Foo
{
public:
static int bar();
};
The function has no arguments and shall return a result based on the type of Foo. (In this toy example, we return the number of bytes of the type, but in the actual application we want to return some meta-data object.)
The specialization works for fully specified types:
// specialization 1: works
template <>
int Foo<int>::bar() { return 4; }
// specialization 2: works
template <>
int Foo<double>::bar() { return 8; }
// specialization 3: works
typedef pair<int, int> IntPair;
template <>
int Foo<IntPair>::bar() { return 2 * Foo<int>::bar(); }
However, I would like to generalize this to types that depend on (other) template parameters themselves.
Adding the following specialization gives a compile-time error (VS2005):
// specialization 4: ERROR!
template <>
template <typename U, typename V>
int Foo<std::pair<U, V> >::bar() { return Foo<U>::bar() + Foo<V>::bar(); }
I am assuming this is not legal C++, but why? And is there a way to implement this type of pattern elegantly?
Partitial specialization is valid only for classes, not functions.
Workaround:
template <typename U, typename V>
class Foo<std::pair<U, V> > {
public:
static int bar() { return Foo<U>::bar() + Foo<V>::bar(); }
};
If you does not want to specialize class fully, use auxiliary struct
template<class T>
struct aux {
static int bar();
};
template <>int aux <int>::bar() { return 4; }
template <>int aux <double>::bar() { return 8; }
template <typename U, typename V>
struct aux <std::pair<U, V> > {
static int bar() { return Foo<U>::bar() + Foo<V>::bar(); }
};
template<class T>
class Foo : aux<T> {
// ...
};
It is perfectly legal in C++, it's Partial Template Specialization.
Remove the template <> and if it doesn't already exists add the explicit class template specialization and it should compile on VS2005 (but not in VC6)
// explicit class template specialization
template <typename U, typename V>
class Foo<std::pair<U, V> >
{
public:
static int bar();
};
template <typename U, typename V>
int Foo<std::pair<U, V> >::bar() { return Foo<U>::bar() + Foo<V>::bar(); }