So I've been trying to understand variadic templates a little bit more,
My goal was to receive all types, expand them, and print them..
I was able to do it in for a function(found some examples) but I was not able to do it for a class
Here I am trying to build a 'Master' to hold many 'Slaves', each Slave is supposed to have a Slave_T inherit from him and then know it's type, and print it on c'tor.
But for some reason I am not able to fix the ambigious compilation error.. I was trying to avoid passing any of the type as parameters to the function.. I tried with enable_if or true/false_type convensions but was unable, anyone has any idea?
This is my code:(function expansion included)
Function expansion that works:
template<typename T, typename... Targs>
void Print(T value, Targs... Fargs) // recursive variadic function
{
Print<T>();
Print(Fargs...); // recursive call
}
template<typename T>
void Print(T = NULL)
{
std::cout << typeid(T).name() << endl;
}
Class Expansion that I need help with:
#include <iostream>
#include <vector>
#include <type_traits>
#include <memory>
using namespace std;
struct Slave {
virtual char const* Type() = 0;
};
template<typename T>
struct Slave_T : public Slave{
virtual char const* Type() {
return typeid(T).name();
}
};
template <typename ...T>
struct Master {
Master()
{
MakeSlave<T...>();
cout << "All Slaves:" << endl;
for (auto const& slave : v){
cout << slave ->Type() << endl;
}
}
private:
template<typename T, typename ...Rest>
void MakeSlave()
{
MakeSlave<Rest...>(); MakeSlave<T>();
}
template<typename T>
void MakeSlave() {
v.push_back(new Slave_T<T>());
}
vector<shared_ptr<Slave>> v;
};
int main()
{
Master<int, double, char> m;
//Print("Hello", '!', 123, 123);
return 0;
}
Thanks!
Alon
First of all: To allow polymorphic templates, you have defined a non-templated pure-virtual base class Slave. Your template class Slave_T must inherit from it (You want a std::vector containing heterogeneous templates, right?). And note that you are using the virtual function defined by the base class Slave. I think you have forgotten to write the base class list before struct Slave_T :)
Second: In that override of the virtual function Type(), you have written Slave<T>::type instead of Slave_T<T>::type. Also note that this sentence needs typename keyword before it, because is a reference to a dependent scope.. But, on the other hand, you have access to the Slave_T template param T, so, why you don't simply use T? :)
Third: Prefer to use std::make_shared instead of a raw new sentences.
Fourth: Prefer std::string instead of C-style raw-strings.
Edit after code fixes:
Template param T of private function MakeSlave() shadows the class variadic template param T. You must have to use other name.
By the way, the error is that in the overloads of makeslave are ambiguous: You have defined a version with template params T and variadic Params, that is, the tipicall HEAD TAIL recursive approach used with variadic packs. But, on the other hand, you also define a version with only one template param. Note that this make ambiguity with the first version, because a variadic pack can be empty, so in your base case the compiler donesn't know what version use.
Solution:
You could use a sentinel type to track when the param list is completely processed. You use this sentinel to enable/disable the base case to avoid the ambiguity:
template <typename ...T>
struct Master {
Master()
{
MakeSlave<T...,_my_centinel_type>();
cout << "All Slaves:" << endl;
for (auto const& slave : v){
cout << slave ->Type() << endl;
}
}
private:
struct _my_centinel_type {};
template<typename U, typename ...Rest>
typename std::enable_if<!std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave()
{
v.push_back( std::make_shared<Slave_T<U>>());
MakeSlave<Rest...>();
}
template<typename U>
typename std::enable_if<std::is_same<U,_my_centinel_type>::value , void>::type MakeSlave(){
//The base case does anything
}
See it in action: http://ideone.com/FqMPXh#
Related
I want to be able to have a template type argument as empty, which case the class just has an empty T, or U, or whatever. I tried to do this defaulting the template argument to a simple lambda:
template <typename U = decltype([]() {})>
On Visual Studio 2019 16.9.3 I don't get the right result when I query the type of U, but by trying to compile on OnlineGDB I found out that this probably shouldn't be compiling anyway because the defaulted argument is defining a new type:
#include <iostream>
template <typename T, typename U = decltype([]() { }) >
struct Planet
{
T T_obj;
[[no_unique_address]] U U_obj;
};
int main()
{
Planet<int, char> planet;
std::cout << "Typename = " << typeid([]() {}).name() << '\n'; // Type here is a lambda, which is correct
std::cout << "Typename of U = " << typeid(planet.U_obj).name() << '\n'; // Type here is int, why?
std::cout << "Typename of U = " << typeid(Planet<int>::U_obj).name() << '\n'; // Type here is int, why?
}
Is this just some sort of bug? If I cannot do 'decltype([] () {})' then I can just define 'struct EmptyType{};' just above the template without a problem.
In C++17, a lambda may not appear in an unevaluated context. This restriction was lifted in C++20, but your compiler might not have implemented this feature yet (even if it already supports [[no_unique_address]], another C++20 feature), so you need to upgrade your compiler. And in any case I would recommend not writing code like this, because it would mean that Planet<int> would not be the same type as Planet<int> (even within the same TU), as a new lambda type will be created every time the default argument is used. void might work better as the default type, and you can give U_obj some private empty class type in the case where U is void.
The correct answer to the question was given by Brian Bi (see above). This post is just a follow-up that started from a comment discussion and was requested by the original poster to be elaborated in more detail and might be helpful to somebody trying achieve the same behaviour. Therefore I decided to post it over here rather than somewhere hidden in the comment. The solutions are not equivalent (e.g. stack vs heap allocation) and partially also have a different interface.
Dummy struct
One possible solution would be to simply pass a dummy struct as a default parameter as follows (Wandbox)
struct DummyStruct {
};
template <typename T, typename U = DummyStruct>
struct Planet {
Planet(T const t, U const u = {})
: t_{t}, u_{u} {
return;
}
T t_;
U u_;
};
Pointer to void
Similarly one could use plain or smart pointers and a default type void. The given constructor will not work with template deduction but you can always write a constructor with smart pointers (Wandbox).
template <typename T, typename U = void>
struct Planet {
// Trick to disable this constructor for type void in order to avoid compilation error
template<typename T1 = T, typename U1 = U,
typename std::enable_if_t<!std::is_same_v<U1,void> && std::is_same_v<U1,U>>* = nullptr>
Planet(T1 const& t, U1 const& u)
: t_{std::make_shared<T>(t)}, u_{std::make_shared<U>(u)} {
return;
}
Planet(T const& t)
: t_{std::make_shared<T>(t)}, u_{nullptr} {
return;
}
std::shared_ptr<T> t_;
std::shared_ptr<U> u_;
};
Variadic templates and tuples
One might as well use variadic templates in combination with tuples and then access them with std::get(...) but the usage might be a bit inconvenient (Wandbox)
template <typename... Ts>
struct Planet {
Planet(Ts const&... t)
: t_{std::make_tuple(t...)} {
return;
}
std::tuple<Ts...> t_;
};
Polymorphic vector
Another possibility in some special cases where the involved containers are derived from a common base class and therefore share a common interface is using a std::vector of smart pointers such as (Wandbox):
struct Parent {
virtual void update() = 0;
};
struct Child: public Parent {
void update() override {
// Do something
return;
}
};
struct Planet {
template <typename... Ts>
Planet(std::shared_ptr<Ts>&... t)
: t_{t...} {
// Static assertion with fold expression
static_assert((std::is_base_of_v<Parent, Ts> && ...), "Template arguments must inherit from 'Parent'.");
return;
}
std::vector<std::shared_ptr<Parent>> t_;
};
In C++, say that I have some class mom. I know that I can make a template function that accepts any class, like:
template <class T> void Iacceptanything(T x)
{
// Do something
}
Now, this works nice, but I would like to make a more restrict template class, something that accepts as T any type that inherits from class mom. I thought about making the function accept mom as only argument type, but in that function I need to do build a template object with the argument, therefore I need its type to be preserved (i.e., my object shouldn't be "pruned down" to only its being an heir of mom).
What I would need is something like:
template <class T:mom> void Iacceptonlysonsofmom(T x)
{
// Do something
}
Is this possible at all?
Use std::enable_if and std::is_base_of.
#include <type_traits>
#include <iostream>
class Base { };
class Derived : public Base { };
class NotDerived { };
// If the return type of foo() is not void, add where indicated.
template <typename T>
typename std::enable_if<std::is_base_of<Base, T>::value /*, some_type*/>::type
foo(T) {
std::cout << "Derived from Base." << std::endl;
}
// If the return type of foo() is not void, add where indicated.
template <typename T>
typename std::enable_if<!std::is_base_of<Base, T>::value /*, some_type*/>::type
foo(T) {
std::cout << "Not derived from Base." << std::endl;
}
int
main() {
Derived d;
NotDerived nd;
foo(d);
foo(nd);
}
Use std::enable_if and std::is_base_of like this:
template <typename T, typename = enable_if<is_base_of<mom, T>::value>::type>
void Iacceptonlysonsofmom(T x)
{
}
If you cannot use C++11, you can achieve the same using Boost's enable_if_c and is_base_of. In the above code, you will need to replace enable_if with enable_if_c and ensure that you use the appropriate namespaces.
As others have suggested you can use enable_if and SFINAE (Substition Failure Is Not An Error) but it can be problematic. It can be fragile across compilers, may cause problems with ODR if not done properly, can cause conflicts with functions pulled in from other scopes (ADL), and may not be the best option.
You do have a couple of alternative options which are less fickle and may make your code easier to understand and maintain. One option (as mentioned in comments) is to use static_assert and is_base_of. This is by far (IMHO) the easiest solution for what you are trying to accomplish. This approach allows you to maintain a single implementation of the function and force a compile time failure if the type is not the base Mom or derived from it.
#include <type_traits>
struct Mom { };
struct Child : Mom { };
struct Uncle { };
template <typename T>
void AcceptOnlyMomAndChildren(T)
{
static_assert(std::is_base_of<Mom, T>::value, "Not derived from Base.");
}
int main()
{
Child child;
Uncle uncle;
AcceptOnlyMomAndChildren(child);
AcceptOnlyMomAndChildren(uncle); // Fails
}
If you need to provide multiple functions that can handle types that are not derived from a particular base class using tag dispatching may make more sense. This is far less fickle across compilers and must easier on the eyes. It can also be easily expanded if you ever need to provide special handling for a type derived from mom (in your example).
#include <type_traits>
#include <iostream>
struct Mom { };
struct Child : Mom { };
struct Uncle { };
template <typename T>
void Func(T&, std::true_type)
{
std::cout << "Derived from Base." << std::endl;
}
template <typename T>
void Func(T&, std::false_type)
{
std::cout << "Not derived from Base." << std::endl;
}
template <typename T>
void Func(T& arg)
{
Func(
arg,
typename std::conditional<
std::is_base_of<Mom, T>::value,
std::true_type, std::false_type>::type());
}
int main()
{
Child child;
Uncle uncle;
Func(child);
Func(uncle);
}
In the above example std::conditional is used to specify the type of an additional argument determine which implementation of Func is called. You can substitute it with your own type traits scheme to support additional implementations if necessary.
Consider the following (invalid) code sample:
// a: base template for function with only one parameter
template<typename T>
void f(T t) { }
// b: base tempalte for function with two parameters
template<typename T1, typename T2>
void f(T1 t1, T2 t2) { }
// c: specialization of a for T = int
template<>
void f<int>(int i) { }
// d: specialization for b with T1 = int - INVALID
template<typename T2>
void f<int, T2>(int i, T2 t2) { }
int main() {
f(true); // should call a
f(true, false); // should call b
f(1); // should call c
f(1, false); // should call d
}
I've read this walk-through on why, in general, partial function template specializations won't work, and I think I understand the basic reasoning: there are cases where function template specializations and overloading would make certain calls ambiguous (there are good examples in the article).
However, is there a reason why this specific example wouldn't work, other than "the standard says it shouldn't"? Does anything change if I can guarantee (e.g. with a static_assert) that the base template is never instantiated? Is there any other way to achieve the same effect?
What I actually want to achieve is to create an extendable factory method
template<typename T>
T create();
which also has a few overloads taking input parameters, e.g.
template<typename T, typename TIn>
T create(TIn in);
template<typename T, typename TIn1, typename TIn2>
T create(TIn1 in1, TIn2 in2);
In order to ensure that all necessary factory methods are present, I use static_assert in the function base templates, so that a compiler error is generated if the create method is called with template arguments for which no specialization has been provided.
I want these to be function templates rather than class templates because there will be quite a lot of them, and they will all use input from the same struct hierarchy, so instantiating 10 factories instead of one comes with some overhead that I'd like to avoid (not considering the fact that the code gets much easier to understand this way, if I can just get it to work...).
Is there a way to get around the problem outlined in the first half of this post, in order to achieve what I've tried to get at with the second half?
In response to iavr:
I could do this with plain overloading, which would (given the templates above) give something like
template<typename TIn2>
A create(bool, TIn2);
template<typename TIn2>
A create(int, TIn2);
if I need two different partial specializations with T = A, TIn1 specified and TIn2 still unspecified. This is a problem, since I have some cases (which are really text-book cases for meta-programming and templates) where I know that, for example, one of the arguments will be a std::string, and the other will be of some type that has a property fields and a property grids, which are of types std::vector<field> and std::vector<grid> respectively. I don't know all the types that will ever be supplied as the second argument - I know for sure that there will be more of them than the ones I currently have implemented - but the implementation of the method will be exactly the same.
While writing up this update, I think I've figured out a way to redesign the implementations so that there is no need for the partial specialization - basically, I do the following to cover the case outlined above:
template<>
A create<A, std::vector<field>, std::vector<grid>>(std::vector<field> fs, std::vector<grid> gs);
and then I have to change the calling signature slightly, but that's OK.
I share your concerns that maybe in this particular case there would be no problem having function template partial specializations, but then again, that's the way it is, so what would be your problem using plain overloading?
// a: base template for function with only one parameter
template<typename T>
void f(T t) { }
// b: base template for function with two parameters
template<typename T1, typename T2>
void f(T1 t1, T2 t2) { }
// c: specialization of a for T = int
void f(int i) { }
// d: specialization for b with T1 = int
template<typename T2>
void f(int i, T2 t2) { }
This also takes less typing and I get this is why you don't want to use function objects (which would have partial specialization).
Here is a simple workaround using a class template specialization:
template <typename, typename...>
struct Creator;
template <typename T, typename TIn>
struct Creator<T, TIn>
{
T call(TIn in)
{
// ...
}
};
template<typename T, typename TIn1, typename TIn2>
struct Creator<T, TIn1, TIn2>
{
T call(TIn1 in1, TIn2 in2)
{
// ...
}
};
template <typename R, typename... Arguments>
R Create(Arguments&&... arguments)
{
return Creator<R, Arguments...>::call(std::forward<Arguments>(arguments)...);
}
If you don't want overloading, and want to be able to specialize from a separate file, then I think you should base it on the solution on the link from your question. It involves making a static method on a class that you specialize. From my reading of the question, you're only interested in specializing on the T, not on the number of arguments, which you intend to forward. In C++11, you can do the following:
#include <iostream>
#include <utility>
using namespace std;
template<typename T>
struct factory_impl;
// Left unspecified for now (which causes compliation failure if
// not later specialized
template<typename T, typename... Args>
T create(Args&&... args)
{
return factory_impl<T>::create(std::forward<Args>(args)...);
}
// Note, this can be specified in a header in another translation
// unit. The only requirement is that the specialization
// be defined prior to calling create with the correct value
// of T
template<>
struct factory_impl<int>
{
// int can be constructed with 0 arguments or 1 argument
static int create(int src = 0)
{
return src;
}
};
int main(int argc, char** argv)
{
int i = create<int>();
int j = create<int>(5);
// double d = create<double>(); // Fails to compile
std::cout << i << " " << j << std::endl;
return 0;
}
Live example http://ideone.com/7a3uRZ
Edit: In response to your question, you could also make create a member function of a class, and pass along some of that data with the call or take action before or after
struct MyFactory
{
template<typename T, typename... Args>
T create(Args&&... args)
{
T ret = factory_impl<T>::create(data, std::forward<Args>(args)...);
// do something with ret
return ret;
}
Foo data; // Example
};
I have a variadic class template deriv which derives off variadic class template base.
I have a function template which takes any type T, and an overload for base<Ts...> types;
How can I get the base<Ts...> overload to be used when passing a const deriv<Ts...>&?
Working example below:
#include <iostream>
#include <tuple>
template<typename... Ts>
struct base
{
std::tuple<Ts...> tuple;
};
template<typename... Ts>
struct deriv : base<Ts...>
{
};
//--------------------------------
template<typename T>
void func(const T&)
{
std::cout << "T" << std::endl;
}
template<typename... Ts>
void func(const base<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
//----------------------------------------
int main()
{
int a;
base <int, double> b;
deriv<int, double> c;
func(a);
func(b);
func(c); // <--- I want func<base<Ts...>> not func<T> to be called here
exit(0);
}
Output from exemplar:
T
base<Ts...>
T
What I want the output to be:
T
base<Ts...>
base<Ts...>
Unless you are ready to re-engineer your code, you cannot, and for a good reason.
Your non-variadic overload of func() is a better match than the variadic version: in fact, when attempting to resolve your function call, the type parameter T for the non-variadic overload will be deduced to be derived<int, double>.
On the other hand, the parameter pack Ts in your variadic overload will be deduced to be int, double. After type deduction, this will practically leave the compiler with these two choices for resolving your call:
void func(const deriv<int, double>&); // Non-variadic after type deduction
void func(const base<int, double>&); // Variadic after type deduction
Which one should be picked when trying to match a call whose argument is of type derived<int, double>?
deriv<int, double> c;
func(c);
Obviously, the first, non variadic overload is a better match.
So how do you get the second overload called instead of the first? You have a few choices. First of all, you can qualify your call by explicitly specifying the template arguments:
func<int, double>(c);
If you do not like that, maybe you can re-think the definition of the non-variadic overload of func(): do you really want it to accept any possible type T? Or are there some types for which you know this overload is not to be invoked? If so, you can use SFINAE techniques and std::enable_if to rule out the undesired matches.
As a further possibility, you can relax a bit the signature of your template function and allow deducing its argument as an instantiation of a certain template class:
template<template<typename...> class T, typename... Ts>
void func(const T<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
This change alone should fix your program's behavior in the way you want.
UPDATE:
If you want your specialized function template to be invoked only for classes derived from any instance of the base<> class template, you can use the std::is_base_of<> type trait and std::enable_if in the following way:
template<template<typename...> class T, typename... Ts>
void func(
const T<Ts...>&,
typename std::enable_if<
std::is_base_of<base<Ts...>, T<Ts...>>::value
>::type* = nullptr
)
{
std::cout << "base<Ts...>" << std::endl;
}
ADDENDUM:
In those situations where template function overloading won't help with your design, notice that you can always resort to partial template specialization. Unfortunately, function templates cannot be specialized, but you can still exploit class template partial specialization and add a helper function to hide the instantiation of that template. This is how you would rewrite your code:
namespace detail
{
template<typename T>
struct X
{
static void func(const T&)
{
std::cout << "T" << std::endl;
}
};
template<template<typename...> class T, typename... Ts>
struct X<T<Ts...>>
{
static void func(const T<Ts...>&)
{
std::cout << "base<Ts...>" << std::endl;
}
};
}
template<typename T>
void func(const T& t)
{
details::X<T>::func(t);
}
The generic-template overload is a better match, since it requires no conversion (except adding const, which both overloads have).
You can get the base-template overload by adding an explicit cast (example):
func(static_cast<base<int, double> &>(c));
(Alternatively, you could forgo the multiple overloads and instead stick some is_base_of helper logic into your main function template's body.)
I have an SFINAE problem:
In the following code, I want the C++ compiler to pick the specialized functor and print "special", but it's printing "general" instead.
#include <iostream>
#include <vector>
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename T::Vec> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
How can I fix it so that the specialized struct is used automatically? Note I don't want to directly specialize the Functor struct on Foo, but I want to specialize it on all types that have a Vec type.
P.S.: I am using g++ 4.4.4
Sorry for misleading you in the last answer, I thought for a moment that it would be simpler. So I will try to provide a complete solution here. The general approach to solve this type of problems is to write a traits helper template and use it together with enable_if (either C++11, boost or manual implementation) to decide a class specialization:
Trait
A simple approach, not necessarily the best, but simple to write would be:
template <typename T>
struct has_nested_Vec {
typedef char yes;
typedef char (&no)[2];
template <typename U>
static yes test( typename U::Vec* p );
template <typename U>
static no test( ... );
static const bool value = sizeof( test<T>(0) ) == sizeof(yes);
};
The approach is simple, provide two template functions, that return types of different sizes. One of which takes the nested Vec type and the other takes ellipsis. For all those types that have a nested Vec the first overload is a better match (ellipsis is the worst match for any type). For those types that don't have a nested Vec SFINAE will discard that overload and the only option left will be the ellipsis. So now we have a trait to ask whether any type has a nested Vec type.
Enable if
You can use this from any library, or you can roll your own, it is quite simple:
template <bool state, typename T = void>
struct enable_if {};
template <typename T>
struct enable_if<true,T> {
typedef T type;
};
When the first argument is false, the base template is the only option, and that does not have a nested type, if the condition is true, then enable_if has a nested type that we can use with SFINAE.
Implementation
Now we need to provide the template and the specialization that will use SFINAE for only those types with a nested Vec:
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename enable_if<has_nested_Vec<T>::value>::type > {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
Whenever we instantiate Functor with a type, the compiler will try to use the specialization, which will in turn instantiate has_nested_Vec and obtain a truth value, passed to enable_if. For those types for which the value is false, enable_if does not have a nested type type, so the specialization will be discarded in SFINAE and the base template will be used.
Your particular case
In your particular case, where it seems that you don't really need to specialize the whole type but just the operator, you can mix the three elements into a single one: a Functor that dispatches to one of two internal templated functions based on the presence of Vec, removing the need for enable_if and the traits class:
template <typename T>
class Functor {
template <typename U>
void op_impl( typename U::Vec* p ) const {
std::cout << "specialized";
}
template <typename U>
void op_impl( ... ) const {
std::cout << "general";
}
public:
void operator()() const {
op_impl<T>(0);
}
};
Even though this is an old question, I think it's still worth providing a couple more alternatives for quickly fixing the original code.
Basically, the problem is not with the use of SFINAE (that part is fine, actually), but with the matching of the default parameter in the primary template (void) to the argument supplied in the partial specialization(typename T::Vec). Because of the default parameter in the primary template, Functor<Foo> actually means Functor<Foo, void>. When the compiler tries to instantiate that using the specialization, it tries to match the two arguments with the ones in the specialization and fails, as void cannot be substituted for std::vector<int>. It then falls back to instantiating using the primary template.
So, the quickest fix, which assumes all your Vecs are std::vector<int>s, is to replace the line
template<class T, class V = void>
with this
template<class T, class E = std::vector<int>>
The specialization will now be used, because the arguments will match. Simple, but too limiting. Clearly, we need to better control the type of the argument in the specialization, in order to make it match something that we can specify as the default parameter in the primary template. One quick solution that doesn't require defining new traits is this:
#include <iostream>
#include <vector>
#include <type_traits>
template<class T, class E = std::true_type>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
template<class T>
struct Functor<T, typename std::is_reference<typename T::Vec&>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
This will work for any Vec type that could make sense here, including fundamental types and arrays, for example, and references or pointers to them.
Another alternative for detecting the existence of a member type is to use void_t. As valid partial specialisations are preferable to the general implementation as long as they match the default parameter(s), we want a type that evaluates to void when valid, and is only valid when the specified member exists; this type is commonly (and, as of C++17, canonically) known as void_t.
template<class...>
using void_t = void;
If your compiler doesn't properly support it (in early C++14 compilers, unused parameters in alias templates weren't guaranteed to ensure SFINAE, breaking the above void_t), a workaround is available.
template<typename... Ts> struct make_void { typedef void type; };
template<typename... Ts> using void_t = typename make_void<Ts...>::type;
As of C++17, void_t is available in the utilities library, in type_traits.
#include <iostream>
#include <vector>
#include <type_traits> // For void_t.
template<class T, class V = void>
struct Functor {
void operator()() const {
std::cerr << "general" << std::endl;
}
};
// Use void_t here.
template<class T>
struct Functor<T, std::void_t<typename T::Vec>> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
struct Foo {
typedef std::vector<int> Vec;
};
int main() {
Functor<Foo> ac;
ac();
}
With this, the output is special, as intended.
In this case, since we're checking for the existence of a member type, the process is very simple; it can be done without expression SFINAE or the type_traits library, allowing us to rewrite the check to use C++03 facilities if necessary.
// void_t:
// Place above Functor's definition.
template<typename T> struct void_t { typedef void type; };
// ...
template<class T>
struct Functor<T, typename void_t<typename T::Vec>::type> {
void operator()() const {
std::cerr << "special" << std::endl;
}
};
To my knowledge, this should work on most, if not all, SFINAE-capable C++03-, C++11-, C++14-, or C++1z-compliant compilers. This can be useful when dealing with compilers that lag behind the standard a bit, or when compiling for platforms that don't have C++11-compatible compilers yet.
For more information on void_t, see cppreference.