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(); }
Related
Say I have some template type...
template <typename T> struct Foo {
Foo(T t) {}
};
Is there a way to pass a specified Foo type to a function so that the function has direct visibility of T?
Ideally I would be able to write something like this...
Foo<int> foo = create<Foo<int>>();
The closest I've been able to come is
template <
template <typename> typename TT,
typename T,
std::enable_if_t<std::is_same<TT<T>, Foo<T>>::value, int> = 0
>
Foo<T> create() {
return Foo<T>(T());
}
which would then be used like
Foo<int> foo = create<Foo, int>();
Thanks for any help.
This form of template template parameter is only allowed in C++17:
template < // v---------- typename here not allowed
template <typename> typename TT,
typename T,
std::enable_if_t<std::is_same<TT<T>, Foo<T>>::value, int> = 0
>
Foo<T> create() {
return Foo<T>(T());
}
You must replace the typename pointed out by class:
template < // v---------- class allowed
template <typename> class TT,
typename T,
std::enable_if_t<std::is_same<TT<T>, Foo<T>>::value, int> = 0
>
Foo<T> create() {
return Foo<T>(T());
}
In C++17, both compiles and are equivalent.
To make your syntax Foo<int> foo = create<Foo<int>>(); work, you simply need to do this:
template <typename T>
T create() {
return T{};
}
If you want to limit what type can be sent, you must create a type trait:
// default case has no typedef
template<typename>
struct first_param {};
// when a template is sent, define the typedef `type` to be equal to T
template<template<typename> class TT, typename T>
struct first_param<TT<T>> {
using type = T;
};
// template alias to omit `typename` everywhere we want to use the trait.
template<typename T>
using first_param_t = typename first_param<T>::type;
Then, use your trait:
template <
typename T,
void_t<first_param_t<T>>* = nullptr
> // ^---- if the typedef is not defined, it's a subtitution error.
T create() {
return T(first_param_t<T>{});
}
You can implement void_t like this:
template<typename...>
using void_t = void;
Live at Coliru
One simple way is to add the sub-type information in Foo directly:
template <typename T> struct Foo {
using type = T;
Foo(T t) {}
};
and then
template <typename FooT>
FooT create() {
return FooT(typename FooT::type{});
}
You might add SFINAE if you want:
template <typename FooT>
auto create()
-> decltype(FooT(typename FooT::type{}))
{
return FooT(typename FooT::type{});
}
If you want really restrict the function to Foo exclusively, you have to create a traits and SFINAE on it.
Why not simply use a tag dispatching, e.g.:
template <class>
struct tag { };
template <class T>
Foo<T> create(tag<Foo<T>>) {
return Foo<T>(T());
}
//...
Foo<int> foo = create(tag<Foo<int>>{});
In C++11
Demo
The gist is to have an entry point function named create that can instantiate a create_helper struct to create the proper type.
We can create our structures using template specialization so that we're forcing a templated class to be passed.
Full code:
template<class T>
struct create_helper
{
static_assert(sizeof(T) == 0, "Need to pass templated type to create");
};
template <class T, template<class> class TT>
struct create_helper<TT<T>>
{
static TT<T> apply()
{
return {T{}};
}
};
template<class T>
auto create() -> decltype(create_helper<T>::apply())
{
return create_helper<T>::apply();
}
And a test:
template<class T>
struct Foo
{
Foo(T t){std::cout << "Constructed Foo with value " << t << std::endl;}
};
int main()
{
Foo<int> foo = create<Foo<int>>();
}
Output:
Constructed Foo with value 0
Class declaration is in a class.h file :
template <typename K, typename T>
class classx
{
...
unsigned int func1(K key);
...
which includes this class.hpp :
template <typename K, typename T>
unsigned int classx<K,T>::func1(K key)
{
return 1;
}
//Func1 for <int, typename T> ????
template <>
template <typename T>
unsigned int classx<int,T>::func1<int, T>(int key) // ERROR!
{
return 1;
}
This results:
error: expected initializer before ‘<’ token
What is the proper way of doing this?
Remove the second set of template parameters from your func1 definition and the template <>:
template <typename T>
unsigned int classx<int,T>::func1(int key)
{
return 1;
}
EDIT:
Additionally, you cannot partially specialize a single function of a template class. If you wish to do so, you will have to partially specialize the entire class.
(this question is not related to C++11/C++14: the examples are compiled using C++03)
enable_bool<T> has a member ::type only when T is bool
template <class T>
struct enable_bool
{};
template <>
struct enable_bool< bool >
{ typedef bool type; };
In the next snippet, the partial specialization is correct (see gcc.godbolt.org)
template <class T, class U, class Enable = T>
struct Foo
{
static int bar() { return 0; }
};
template <class T, class U>
struct Foo< T, U, typename enable_bool<T>::type >
{
static int bar() { return 1; }
};
int main()
{
return Foo <int, bool>::bar();
}
As enable_bool<T>::type already corresponds to T (when T is bool)
we are tempted to factorize parameters T and Enable.
But compiler complains (see gcc.godbolt.org)
template <class T, class U>
struct Foo
{
static int bar() { return 0; }
};
template <class T, class U> //ERROR non-deducible template parameter 'T'
struct Foo< typename enable_bool<T>::type, U >
{
static int bar() { return 1; }
};
Why compiler cannot deduce template parameter T in this above partial specialization?
Finally the question was not even related to SFINAE!
Consider this very simple snippet without SFINAE:
enable<T>::type is always same as T whatever the provided T type.
template <class T>
struct enable
{ typedef T type; }; // Enable always
template <class U, class V>
struct Foo
{
static int bar() { return 0; }
};
template <class X, class Y> //ERROR non-deducible parameter 'X'
struct Foo< typename enable<X>::type, Y >
{
static int bar() { return 1; }
};
int main()
{
return Foo<int, bool>::bar();
}
When compiler tries to match Foo<int, bool> with Foo<typename enable<X>::type,Y>
1st param U = int <--> enable<X>::type => Cannot deduce X
2nd param V = bool <--> Y
Compiler is not designed to deduce X from equation int = enable<X>::type.
Therefore, compiler needs some help from developer.
Another parameter is required: Enable.
The below fixed snippet add the Enable class template parameter.
The compiler performs the following matching:
1st param U =int <--> X
2nd param V =bool<--> Y
3rd param Enable=int <--> enable<X>::type (deduced X from 1st param)
(3rd param is int because declaration class Enable=U means by default 3rd param same as 1st one)
Fixed snippet:
template <class T>
struct enable
{ typedef T type; }; // Enable always
template <class U, class V, class Enable = U>
struct Foo
{
static int bar() { return 0; }
};
template <class X, class Y> // Compiler can deduce 'X'
struct Foo< X, Y, typename enable<X>::type >
{
static int bar() { return 1; }
};
int main()
{
return Foo<int, bool>::bar();
}
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).
There is such function definition:
template<>
template<>
void object::test<1>()
{
}
What does it mean that there are double template<>?
EDIT:
I extracted code which is valid for this example:
#include <iostream>
template <class U>
class A {
template <int n>
void test() {
}
};
template <class T>
class B {
public:
typedef A<T> object;
};
typedef B<int>::object object;
template<>
template<>
void object::test < 1 > () {
}
int main() {
return 0;
}
This code compiles under g++.
Source: TUT test framework
For example,
template<class T = int> // Default T is int
class object<T> {
template<int R> void test ();
};
Your code:
template<> // T is fixed
template<> // R is fixed
void object<>::test<1>() // T is default int, R is 1
{
}
is equivalent to:
template<> // T is fixed
template<> // R is fixed
void object<int>::test<1>() // T is int, R is 1
{
}
This is the template specialization of a class template member function template (did I get that right?), with a default parameter for the template. Look at this:
template<typename T = int>
struct X {
template<typename U>
void foo(U u);
};
template<>
template<>
void X::foo(float f) { }
This introduces a specialization for the case where the template parameter of X is int and the argument to X<int>::foo is float. This case is slightly different from yours, we don't have to provide the template argument explicitly after the name of the member function as it can be deduced. Your function has a non-type template argument which cannot be deduced and as such must be provided.
What confused me the most is the default template argument and I'm unsure if it is good practice to use skip it. I'd provide it for every specialization to avoid confusion.
That looks to me like a specialization of a function template within a class template. For example, consider the following class template definition:
template <int m=1>
class object
{
public:
template <int n>
void test();
};
// This differs from your example, by the addition of `<>` after `object`, but it's as
// close as I can come to valid code true to your example
template<>
template<>
void object<>::test<1>()
{
}