Possibly easy to solve, but its hard to find a solution to this:
Is it possible to (partially) specialize for a whole set of types?
In the example "Foo" should be partially specialized for (T,int) and (T,double) with only one template definition.
What I can do is define a specialisation for (T,int). See below. But, it should be for (T,int) and (T,double) with only one function definition (no code doubling).
template <typename T,typename T2>
struct Foo
{
static inline void apply(T a, T2 b)
{
cout << "we are in the generic template definition" << endl;
}
};
// partial (T,*)
template <typename T>
struct Foo<T, int > // here something needed like T2=(int, double)
{
static inline void apply(T a, T2 b)
{
cout << "we are in the partial specialisation for (T,int)" << endl;
}
};
Any ideas how to partially specialize this for (T,int) and (T,double) with one template definition?
If I understood your question correctly, then you can write a base class template and derive from it, as illustrated below:
template <typename T, typename U>
struct Foo_Base
{
static inline void apply(T a)
{
cout << "we are in the partial specialisation Foo_Base(T)" << endl;
}
};
template <typename T>
struct Foo<T, int> : Foo_Base<T, int> {};
template <typename T>
struct Foo<T, double> : Foo_Base<T, double> {};
Although its not one template definition (as you asked for), but you can avoid the code duplication.
Demo : http://www.ideone.com/s4anA
I believe you could do this using Boost's enable_if to enable the partial specialisation for just the types you want. Section 3.1 shows how, and gives this example:
template <class T, class Enable = void>
class A { ... };
template <class T>
class A<T, typename enable_if<is_integral<T> >::type> { ... };
Related
Consider the following code:
#include <iostream>
template <template<class...> class C>
struct foo {
foo() { std::cout << "base case\n";}
};
template <template<class> class C>
struct foo< C > {
foo() { std::cout << "single param case\n";}
};
template <template<class,class> class C>
struct foo< C > {
foo() { std::cout << "two param case\n";}
};
template <typename T> struct bar1 {};
template <typename T,typename U> struct bar2 {};
template <typename T,typename U,typename V> struct bar3 {};
template <typename...T> struct barN {};
int main() {
foo<bar1> f;
foo<bar2> g;
foo<bar3> h;
foo<barN> n;
}
Output is (gcc10.2#godbolt):
single param case
two param case
base case
base case
Suppose barX is given and that I have other templates with varying number of type parameters. Some variadic some not.
Is it possible to write a specialization that only matches the variadic template (barN in the above example)?
Very interesting question. Unfortunately the answer is No.
There is no general way to determine if a template had a template parameter pack or just a bunch of regular template parameters with or without defaults.
The reason is that non-variadic templates can bind to variadic template template parameters and the concrete types of a template can bind to a template parameter pack.
So effectively the information is not available via deduction/specialization. And in general this is good - without this feature variadic templates would lose much of their power.
But if we could limit the maximum length of template arguments we could write a trait with a bunch of template specializations. This works because of partial ordering (as you have shown in your question): godbolt
We can determine whether a class template that can be instantiated with 0 template arguments is genuinely variadic or (merely) has defaults for all its non-variadic template arguments, by counting the arguments to an 0-argument instantiation:
template<class> constexpr unsigned argc_v;
template<template<class...> class C, class... A> constexpr unsigned argc_v<C<A...>> = sizeof...(A);
template<template<class...> class, class = void> constexpr bool is_variadic_v = false;
template<template<class...> class C> constexpr bool is_variadic_v<C, std::void_t<C<>>> = argc_v<C<>> == 0;
Then we can use this to build a set of specializations that respectively accept only variadic, 1-argument (with possible default) and 2-argument (with possible default/s) class templates:
template<template<class...> class, class = std::true_type>
struct foo;
template<template<class...> class C>
struct foo<C, std::bool_constant<is_variadic_v<C>>> {
foo() { std::cout << "variable case\n"; }
};
template<template<class> class C>
struct foo<C, std::bool_constant<!is_variadic_v<C> && argc_v<C<void>> == 1>> {
foo() { std::cout << "single param case\n";}
};
template<template<class, class> class C>
struct foo<C, std::bool_constant<!is_variadic_v<C> && argc_v<C<void, void>> == 2>> {
foo() { std::cout << "two param case\n";}
};
I'm a bit disappointed that the latter argc_v tests are necessary (in C++20 mode); I think it's something to do with P0522 / CWG150.
Demo.
I am trying to leave in struct A one function foo (prints 0) if its parameter have template method isA<void> and another (prints 1) if haven't. This code (reduced to minimal example below) compiles (tried with gcc 6.1.0 and clang-3.9.0 with explicit --std=c++14 option) and runs.
But it prints 1, though, I am sure, that it shall print 0. I wonder where am I wrong, but real question is: how to make this work correct?
Please only C++14 solutions.
#include <type_traits>
#include <iostream>
#include <utility>
using std::enable_if;
using std::declval;
using std::true_type;
using std::false_type;
using std::cout;
template<int M>
struct ObjectX
{
template<typename C>
bool isA() { return false; }
};
struct XX : ObjectX<23456> {
int af;
};
template <typename ObjType> using has_dep = decltype(declval<ObjType>().template isA<void>());
template <typename, typename = void>
struct has_isa : public false_type {};
template <typename ObjType>
struct has_isa<ObjType, has_dep<ObjType> > : public true_type {};
template<typename ObjType>
struct A
{
template<typename T = void>
typename enable_if<has_isa<ObjType>::value, T>::type
foo() {
cout << "called foo #0" << "\n";
}
template<typename T = void>
typename enable_if<!has_isa<ObjType>::value, T>::type
foo() {
cout << "called foo #1" << "\n";
}
};
int
main()
{
A<XX> axx;
// XX().template isA<void>(); -- to check, that we can call it and it exists
axx.foo();
return 0;
}
There are two problems in this program.
First, has_dep<XX> is bool. When we try has_dep<XX>, adding the default template arguments means this is really has_dep<XX, void>. But the specialization is has_dep<XX, bool> - which doesn't match what we're actually looking up. bool does not match void. That's why has_dep<XX> is false_type. The solution to this is std::void_t, and I'd suggest reading through that Q/A to get an idea for why it works. In your specialization, you need to use void_t<has_dep<ObjType>> instead.
Second, this is not right:
template<typename T = void>
typename enable_if<has_isa<ObjType>::value, T>::type
SFINAE only happens in the immediate context of substitution, and class template parameters are not in the immediate context of function template substitution. The right pattern here is:
template <typename T = ObjType> // default to class template parameter
enable_if_t<has_isa<T>> // use the function template parameter to SFINAE
foo() { ... }
Make those two fixes, and the program works as intended.
Your sfinae fails because has_isa chooses the wrong specialization.
The use of has_isa<T> must be either the default implementation or the specialized version.
As you defined, you have a default argument to void:
// default argument ---------v
template <typename, typename = void>
struct has_isa : public false_type {};
Then in the expression has_isa<T>, the second parameter must be void. It's roughly the same as writing has_isa<T, void>.
The problem is this:
template <typename ObjType>
struct has_isa<ObjType, has_dep<ObjType>> : public true_type {};
// ^--- what's that type?
Even though template partial ordering would consider this "overload" more specialized, it won't be chosen. Look at the definition of has_dep:
struct XX {
template<typename C> bool isA() { return false; }
};
template <typename ObjType>
using has_dep = decltype(declval<ObjType>().template isA<void>());
Hey, that type has_dep<T> is the return type of t.isA<void>() which is bool!
So the specialized version look like this:
template <typename ObjType>
struct has_isa<ObjType, has_dep<ObjType>> : public true_type {};
// ^--- really, this is bool in our case
So in order for this to work, you must call has_isa<T, bool>. As this is impractical, you should define your specialization as this:
template <typename ObjType>
struct has_isa<ObjType, void_t<has_dep<ObjType>>> : public true_type {};
Where void_t is defined as so:
template<typename...>
using void_t = void; // beware for msvc
As such, has_isa<T> will always consider the specialization, because we send void as the second template parameter, and now our specialization always result with void as second parameter.
Also, as stated by Barry, your function is not correctly formed as sfinae only appears in immediate context. You should write it like this:
template<typename T = ObjType>
typename enable_if<has_isa<T>::value, void>::type
foo() { // ^--- sfinae happens with T
cout << "called foo #0" << "\n";
}
If you don't wish to expose the template parameter, simply make the function private:
template<typename ObjType>
struct A {
public:
void foo() {
foo_impl();
}
private:
template<typename T = ObjType>
typename enable_if<has_isa<T>::value, void>::type
foo_impl() {
cout << "called foo #0" << "\n";
}
template<typename T = ObjType>
typename enable_if<!has_isa<T>::value, void>::type
foo_impl() {
cout << "called foo #1" << "\n";
}
};
Your problem is that you specialize the wrong class:
You should force has_dep to return void.
template <typename ObjType> using has_dep = decltype(static_cast<void>(declval<ObjType>().template isA<void>()));
So here
template <typename ObjType>
struct has_isa<ObjType, has_dep<ObjType> > : public true_type {};
// It is really <bjType, void> you specialize.
So, first consider the following where template parameters are known implicitly from the function arguments:
#include <iostream>
using namespace std;
class A {};
class B {};
template <class T1, class T2>
class C {
T1 a;
T2 b;
};
template <class T1>
class D {
T1 a;
};
template <template<class, class> class TC, class TA, class TB>
void foo(TC<TA, TB> c) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(TD<TA> d){
std::cout << "T<T>" << std::endl;
};
int main() {
C<A,B> c;
D<A> d;
foo(c);
foo(d);
}
And output is as you'd expect:
T<T,T>
T<T>
However, what if I don't have an instance of class C and D so I need to explicitly call the correct overload? How would this be done? i.e., have a main() that consists of:
int main() {
foo<C<A,B> >();
foo<D<A> >();
}
I've experimented with a few overloads of foo() as shown below:
template <template<class, class> class TC>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD>
void foo(){
std::cout << "T<T>" << std::endl;
};
template <template<class, class> class TC, class TA, class TB>
void foo() {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(){
std::cout << "T<T>" << std::endl;
};
However, this (and all permutations I've been able to think of) simply results in a series of errors along the lines of the (abbreviated) output shown below
prog.cpp: In function 'int main()':
prog.cpp:44:18: error: no matching function for call to 'foo()'
foo<C<A,B> >();
^
prog.cpp:44:18: note: candidates are:
prog.cpp:19:6: note: template<template<class, class> class TC> void foo()
void foo() {
^
prog.cpp:19:6: note: template argument deduction/substitution failed:
prog.cpp:24:6: note: template<template<class> class TD> void foo()
void foo(){
^
prog.cpp:24:6: note: template argument deduction/substitution failed:
Is what I'm looking to do even allowable? If so, where am I messing up?
---- EDIT ----
So as apple apple pointed out if my main() is as follows:
int main() {
foo<C, A, B>();
foo<D, A>();
}
I get the output as expected.
However, my real-world case winds up being more complex. I'll expand a bit here. The legacy code has (hundreds) of typedefs defined in headers elsewhere along the lines of:
typedef C<A, B> type_117;
typedef D<A> type_252;
The class I'm working on is templated and is instantiated with one of those typedefs as the templating argument. So something along the lines of:
template <class Type>
class Test
{
public:
Test();
SomeClass mSC;
}
Test::Test()
: mSC(foo<Type>())
{
};
where Test was instantiated as
Test<type_117> aTest;
So I've been trying to figure out how to write foo() for this context. At the point I call foo() within my Test's initializer am I able to "decompose" it to produce the <C,A,B> form? Or have I hit a roadblock and need to rework some of the existing framework?
template<class T>struct tag_t{constexpr tag_t(){}};
template<class T>constexpr tag_t<T> tag{};
these are type tags. They can be passed to functions without an instance of the type.
Template functions will deduce on them.
template <template<class, class> class TC, class TA, class TB>
void foo(tag_t<TC<TA, TB>>) {
std::cout << "T<T,T>" << std::endl;
};
template <template<class> class TD, class TA>
void foo(tag_t<TD<TA>>){
std::cout << "T<T>" << std::endl;
};
at call site do foo(tag<type_117>) and bob, as they say, is your uncle.
In C++98 (ick):
template<class T>struct tag_t{};
foo(tag_t<type_117>());
You may use partial specialization (and variadic template):
template <class Type>
class Test;
template <template <typename ...> class C, typename ... Ts>
class Test<C<Ts...>>
{
public:
Test() : mSC(foo<C, Ts...>()) {}
SomeClass mSC;
};
Take in count that partial specialization is forbidden for functions; so is difficult to do what do you exactly asked.
The suggestion from apple apple (chenge the calling as foo<C, A, B>() is a good one but, if you want to maintain the original call (foo<C<A, B>>()) you can use the fact that the partial specialization is allowed for structs/classes and create a partial specialization for a functor; something like
template <typename>
struct bar;
template <template<typename, typename> class Tc, typename Ta, typename Tb>
struct bar<Tc<Ta,Tb>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta, Tb>>()" << std::endl; }
};
template <template<typename> class Tc, typename Ta>
struct bar<Tc<Ta>>
{
void operator() ()
{ std::cout << "bar<Tc<Ta>>()" << std::endl; }
};
The problem (?) is that, calling it, you can't call as bar<C<A,B>>() od bar<D<A>>() but you have to add a couple of parentheses:
bar<C<A,B>>()();
bar<D<A>>()();
or
bar<C<A,B>>{}();
bar<D<A>>{}();
I suppose that the functor solution can solve also the problem of the Edit part of your question.
If the added couple of parentheses is a problem, you can (as suggested by Jarod42 (thanks!)) wrap the call in a template function, as follows
template <typename T>
void bar ()
{ bar<T>{}(); }
So you can call the bar<C<A, B>>() function and manage the call in the specialized bar<C<A, B>> struct.
Observe also the solution from Jarod42: depending on your requirements, you could develop only a version of the partial specialization of bar.
-- EDIT --
The OP ask
I'm not that familiar with partial specialization; could you expand a bit on how what I was trying was?
Specialization (partial and full) is a big, big topic.
Just some example, to give an idea.
Given a template class/struct
template <typename X, typename Y>
struct foo
{ };
you can partial specialize it as follows (by example)
template <typename X>
struct foo<X, X>
{ };
when the specialization maintain a template variable, or you can full specialize as follow (by example)
template <>
struct foo<int, long>
{ };
where all template argument are fixed.
Well: with function you can full specialize but not partial specialize.
So you can write a template function
template <typename X, template Y>
void foo ()
{ }
and full specialize it
template <>
void foo<int, long> ()
{ }
but you can't partial specialize it; so you can't write (is an error)
template <typename X>
void foo<X, X> ()
{ }
Considering class templates, it is possible to provide template specializations for certain types of groups using type traits and dummy enabler template parameters. I've already asked that earlier.
Now, I need the same thing for function templates: I.e., I have a template function and want a specialization for a group of types, for example, all types that are a subtype of a class X. I can express this with type traits like this:
std::enable_if<std::is_base_of<X, T>::value>::type
I thought about doing it this way:
template <typename T, typename ENABLE = void>
void foo(){
//Do something
}
template <typename T>
void foo<T,std::enable_if<std::is_base_of<A, T>::value>::type>(){
//Do something different
}
However, this does not work since partial specialization is not allowed for function templates. So how to do it then? Maybe a default parameter with the type trait as type? But how does the code look like then?
Overloads:
void foo_impl(T, std::false_type);
void foo_impl(T, std::true_type);
foo(T t) { foo_impl(t, std::is_base_of<A, T>()); }
The closest to what you're asking is enable_if on the return type:
template<typename T> typename std::enable_if<std::is_same<T, int>::value>::type foo();
template<typename T> typename std::enable_if<std::is_same<T, char>::value>::type foo();
However, dispatching to a helper function or class is likely to be more readable and efficient.
Helper function:
template<typename T> void foo_helper(std::true_type);
template<typename T> void foo_helper(std::false_type);
template<typename T> void foo() { foo_helper(std::is_same<T, int>()); }
Helper class:
template<typename T, bool = std::is_same<T, int>::value> struct foo_helper {};
template<typename T> struct foo_helper<T, true> { static void foo(); };
template<typename T> struct foo_helper<T, false> { static void foo(); };
template<typename T> void foo() { foo_helper<T>::foo(); }
Do the actual implementation (partial specializations etc..) in class templates and write a small wrapper template function that does nothing but call a static function in your class templates.
Tried a few things and finally came up with the correct syntax myself - sorry for asking. I didn't know that enable_if has a second parameter. By using this parameter and a default value, it is possible.
Here is the answer
template<typename T>
void foo(typename std::enable_if<std::is_base_of<A, T>::value,int>::type ENABLER = 0){
std::cout << "T is a subclass of A!";
}
template<typename T>
void foo(typename std::enable_if<!std::is_base_of<A, T>::value,int>::type ENABLER = 0){
std::cout << "T is NOT a subclass of A";
}
Is it possible to have multiple versions of the same class which differ only in the number of template arguments they take?
For instance:
template<typename T>
class Blah {
public:
void operator()(T);
};
template<typename T, typename T2>
class Blah {
public:
void operator()(T, T2);
};
I'm trying to model functor type things which can take a variable number of arguments (up to the number of different templates that were written out).
The simplest answer would be to have just one template, with the maximum number you want to support and use void for a default type on all but the first type. Then you can use a partial specialization as needed:
template<typename T1, typename T2=void>
struct foo {
void operator()(T1, T2);
};
template <typename T1>
struct foo<T1, void> {
void operator()(T1);
};
int main() {
foo<int> test1;
foo<int,int> test2;
test1(0);
test2(1,1);
}
A template can have only one base definition. If you need a variable number of arguments and you don't want to use "null type" constructions as #awoodland suggests, and if you have a C++0x compiler, then you can use variadic templates:
template <typename ...Dummy> struct foo; // base case, never instantiated!
template <typename T> struct foo<T> { /*...*/ }; // partial spec. for one parameter
template <typename T, typename U> struct foo<T, U> { /*...*/ }; // ditto for two
This is untested code, I don't have a version of boost handy, but here goes anyway
#include "boost/tuple.h"
template <class T>
class Blah;
template <class T>
class Blah< boost::tuple<T> >
{
void operator()(T arg);
};
template <class T, class U>
class Blah< boost::tuple<T, U> >
{
void operator()(T arg1, U arg2);
};
etc. etc.