I have seen a lot of links introducing the variadic templates. But I have never seen any compilable example that demonstrates this approach.
Could someone provide me with some links in which such compilable examples can be found?
One of the simplest possible examples is the following implementation of max which isn't even templated on types.
int maximum(int n)
{
return n;
}
template<typename... Args>
int maximum(int n, Args... args)
{
return max(n, maximum(args...));
}
Only slightly more complex is the canonical printf implementation:
void printf(const char *s)
{
while (*s)
{
if (*s == '%' && *(++s) != '%')
throw "invalid format string: missing arguments";
std::cout << *s++;
}
}
template<typename T, typename... Args>
void printf(const char* s, T value, Args... args)
{
while (*s)
{
if (*s == '%' && *(++s) != '%')
{
std::cout << value;
printf(s, args...); // call even when *s == 0 to detect extra arguments
return;
}
std::cout << *s++;
}
throw "extra arguments provided to printf";
}
Variadic templates are a C++0x feature that primarily targets authors of generic libraries. I would not expect to see them in "user code". For example, in the C++0x standard library they are used in a lot of places: std::function, std::async, std::reference_wrapper, std::tuple, std::packaged_task, ...
To give you an example I'll show you how a reference_wrapper might be implemented with respect to variadic templates:
template<class T>
class reference_wrapper
{
T *ptr;
public:
explicit reference_wrapper(T& thing) : ptr(&thing) {}
explicit reference_wrapper(T&& ) = delete;
operator T&() const {return *ptr;}
template<class... Args>
decltype( declval<T&>()(declval<Args>()...) )
operator()(Args&&... args) const
{
return (*ptr)(forward<Args>(args)...);
}
};
This is not perfectly conforming to the standard draft but it is supposed to be compilable with little modification. It demonstrates multiple C++0x features:
deleted functions (disabling the constructor for rvalues)
rvalue references (detecting rvalue arguments to the constructor, perfect forwarding)
type deduction via decltype
standard library function template declval to create objects for the purpose of building an expression for decltype (GCC does not yet offer this function template. You have to write it yourself)
variadic templates (accepting an arbitrary number of parameters)
The purpose of the variadic member template is to forward arguments to the object referred to by ptr. This should work in case T is a function pointer type or a class type with overloaded function call operator.
cheers!
s
Wikipedia is good starting point.
Gregor, Douglas; Jaakko Järvi; Gary Powell (9 September 2006). "Variadic Templates (Revision 3)".
A very simple example of variadic template:
Suppose we want to have a function which takes variable number of arguments and prints them all. For ex:
print("Hello", 1, 3.14, 5L);
For that functionality to work, we would basically require two functions:
First one, a function which takes variable number of arguments:
template<typename T, typename... Args>
void print(T t, Args ...args){
std::cout << t << ", ";
print(args...);
}
Some explanation:
1.) Parameter Packs denoted by ellipsis(...), that appear in parameter list.
typename...Args
| | << Optional whitespace. Can have multiple whitespaces in between them
Args...args
That means, these all are same.
typename ...args
typename...args
typename ... args
So, you don't have to worry about the correct position of the whitespace in there. Though, IMO at most one whitespace should be used as a best practice.
2.) Pack Expansion: A pattern followed by an ellipsis.
print(args...); //expand when you wish to use them
3.) Parameter pack accepts zero or more template args. So, print(T t, Args... args) accepts one or more args.
Once you understand that, we can visualize the call flow as below:
print("Hello", 1, 3.14, 5L);
translates into:
print(string, int, float, long);
which calls
print(int, float, long);
which calls
print(float, long); // say Level 2
which calls
print(long); // say Level 1
which calls
print(); // say Level 0
If you have followed the Point#3 carefully, you must have realized that print(T t, Args... args) can't handle call at Level 0.
So we need another function here with same name to catch up at any level >=0.
Second one, a function to grab the call at the top of call stack:
Catch at level 0:
void print(){}
or, Catch at level 1:
template<typename T>
void print(T t){ std::cout << t;}
or, Catch at level 2:
template<typename T, typename U>
void print(T t, U u){ std::cout << t << ", " << u;}
so on...
Any of these would work. Hope this helps you next time you go about writing such function or class.
This is an example of variadic templates that I put up on my blog:
http://thenewcpp.wordpress.com/2011/11/23/variadic-templates-part-1-2/
It compiles. It demonstrates finding the largest type from a group of types.
#include <type_traits>
template <typename... Args>
struct find_biggest;
//the biggest of one thing is that one thing
template <typename First>
struct find_biggest<First>
{
typedef First type;
};
//the biggest of everything in Args and First
template <typename First, typename... Args>
struct find_biggest<First, Args...>
{
typedef typename find_biggest<Args...>::type next;
typedef typename std::conditional
<
sizeof(First) >= sizeof(next),
First,
next
>::type type;
};
Variadic templates are part of the C++0x standard which is not yet officially released. They are supported by gcc since version 4.3, but you need to enable support for C++0x by adding the compiler switch -std=c++0x.
Before C++11, you can create template only with the fixed count of parameters.
Firts template for the function with one parameter.
Second template for the function with two parameters.
... i.e.
Since C++11 you can write only one template, compiler will generate required function itself.
Good example
http://eli.thegreenplace.net/2014/variadic-templates-in-c/
another syntax: expanding, e.g.
template<typename VAL, typename... KEYS>
class MyMaps
{
typedef std::tuple< std::map<KEYS,VAL>... > Maps;
}
hence:
MyMaps<int,int,string>:Maps
is now actually:
std::tuple<std::map<int,int>,std::map<string,int> >
Related
template<typename T, size_t M, size_t K, size_t N, typename std::enable_if_t<std::is_floating_point<T>::value, T> = 0>
void fastor2d(){//...}
I copied this line of code from cpp-reference(only the std::enable_if part, i do need T and all three of the size_t's), because i would like to use this function only when floating_types are used on it ... it does not compile.
Could somebody explain to me, why, and what it even does? While i am at it, how do you call this function afterwards?
Every tutorial or question here on SO gets bombed with answers, and that is great, but to someone who does not understand jacks*** of what is happening, even those are not really helpful.(sry, if possibly slightly agitated or aggressive)
EDIT: i greatly appreciate all answers as of now, i realize that my wording might have been a bit off ... i understand what a template parameter is, and know the difference between runtime and compiletime etc, but i just cant get a good grasp of the syntax behind std::enable_if
EDIT2:
template<typename T, size_t M, size_t K, size_t N, typename = std::enable_if_t<std::is_integral<T>::value>>
void fastor2d(){
Fastor::Tensor<T,M,K> A; A.randInt();
}
This is literally the only thing i need changed. Notice the random() part
template<typename T, size_t M, size_t K, size_t N, typename = std::enable_if_t<std::is_floating_point<T>::value>>
void fastor2d(){
Fastor::Tensor<T,M,K> A; A.random();
}
I'll try to explain this as simple as possible not to go into the language details too much since you asked for it.
Template arguments are compile time arguments (they do not change during the run-time of your application). Function arguments are run-time and have a memory address.
Calling this function would look something like this:
fastor2d<Object, 1, 2, 3>();
In the <> brackets you see the compile-time arguments or more accurately the template parameters, and the function in this case takes 0 runtime arguments in the () brackets. The last compile time argument has a default argument which is used to check whether the function should compile at all (enable_if type). If you want to know more clearly what enable if does you should search for the term SFINAE, which is a template metaprogramming technique used to determine whether a function or class should exist or not.
Here is a short SFINAE example:
template<typename T, typename = std::enable_if_t<std::is_floating_point<T>::value>>
void function(T arg)
{
}
function(0.3f); //OK
function(0.0); //OK double results in std::is_floating_point<double>::value == true
function("Hello"); //Does not exist (T is not floating point)
The reason the third function call fails, is because the function does not exist. This is because the enable if caused the function not to exist when the compile-time bool that is passed in as its' template argument is false.
std::is_floating_point<std::string>::value == false
Do note that a lot of people agree that the SFINAE syntax is horrible and that a lot of SFINAE code will not be necessary anymore with the introduction of concepts and constraints in C++ 20.
Rather than a top-down approach starting with you code snippet, I'll take a bottom-up approach to explain some important details about templates and what tools and techniques are involved.
At heart, templates are a tool that let you write C++ code that applies to a range of possible types, not strictly for a fixed type. In a statically-typed language, this is firstly a great tool for reusing code without sacrificing type safety, but in C++ in particular, templates are very powerful because they can be specialized.
Every template declaration begins with the keyword template, and a list of type or non-type (i.e value) parameters. Type parameters use the special keyword typename or class, and are used to let your code work over a range of types. Non-type parameters simply use the name of an existing type, and these let you apply your code to a range of values that are known at compile-time.
A very basic templated function might look like the following:
template<typename T> // declare a template accepting a single type T
void print(T t){ // print accepts a T and returns void
std::cout << t; // we can't know what this means until the point where T is known
}
This lets us reuse code safely for a range of possible types, and we can use it as follows:
int i = 3;
double d = 3.14159;
std::string s = "Hello, world!";
print<int>(i);
print<double>(d);
print<std::string>(s);
The compiler is even smart enough to deduce the template parameter T for each of these, so you can safely get away with the following, functionally identical code:
print(i);
print(d);
print(s);
But suppose you want print to behave differently for one type. Suppose, for example, you have a custom Point2D class that needs special handling. You can do this with a template specialization:
template<> // this begins a (full) template specialization
void print<Point2D>(Point2D p){ // we are specializing the existing template print with T=Point2D
std::cout << '(' << p.x << ',' << p.y << ')';
}
Now, anytime we use print with T=Point2D, the specialization is chosen. This is really useful, for example, if the generic template just doesn't make sense for one specific type.
std::string s = "hello";
Point2D p {0.5, 2.7};
print(s); // > hello
print(p); // > (0.5,2.7)
But what if we want to specialize a template for many types at once, based on a simple condition? This is where things become a little meta. First, let's try to express a condition in a way that lets them be used inside templates. This can be a little tricky because we need compile-time answers.
The condition here will be that T is a floating point number, which is true if T=float or T=double and false otherwise. This is actually fairly simple to achieve with template specialization alone.
// the default implementation of is_floating_point<T> has a static member that is always false
template<typename T>
struct is_floating_point {
static constexpr bool value = false;
};
// the specialization is_floating_point<float> has a static member that is always true
template<>
struct is_floating_point<float> {
static constexpr bool value = true;
};
// the specialization is_floating_point<double> has a static member that is always true
template<>
struct is_floating_point<double> {
static constexpr bool value = true;
}
Now, we can query any type to see if it's a floating point number:
is_floating_point<std::string>::value == false;
is_floating_point<int>::value == false;
is_floating_point<float>::value == true;
is_floating_point<double>::value == true;
But how can we use this compile-time condition inside another template? How can we tell the compiler which template to choose when there are many possible template specializations to choose from?
This is achieved by taking advantage of a C++ rule called SFINAE, which in basic English, says, "when there are many possible template specializations to choose from, and the current one doesn't make sense*, just skip it and try the next one."
There's a list of errors, when attempting to substitute template arguments into templated code, that cause the template to be ignored without an immediate compiler error. The list is a bit long and complex.
One possible way that a template doesn't make sense is if it tries to use a type that doesn't exist.
template<typename T>
void foo(typename T::nested_type x); // SFINAE error if T does not contain nested_type
This is the exact same trick that std::enable_if uses under the hood. enable_if is a template class accepting a type T and a bool condition, and it contains a nested type type equal to T only when the condition is true. This is also pretty easy to achieve:
template<bool condition, typename T>
struct enable_if {
// no nested type!
};
template<typename T> // partial specialization for condition=true but any T
struct enable_if<true, T> {
typedef T type; // only exists when condition=true
};
Now we have a helper that we can use in place of any type. If the condition we pass is true, then we can safely use the nested type. If the condition we pass is false, then the template is no longer considered.
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, void>::type // This is the return type!
numberFunction(T t){
std::cout << "T is a floating point";
}
template<typename T>
typename std::enable_if<!std::is_floating_point<T>::value, void>::type
numberFunction(T t){
std::cout << "T is not a floating point";
}
I completely agree that std::enable_if<std::is_floating_point<T>::value, void>::type is a messy way to spell out a type. You can read it as "void if T is floating point, and otherwise stop and try the next overload"
Finally, to take apart your example:
// we are declaring a template
template<
typename T, // that accepts some type T,
size_t M, // a size_t M,
size_t K, // a size_t K,
size_t N, // a size_t N,
// and an unnamed non-type that only makes sense when T is a floating point
typename std::enable_if_t<std::is_floating_point<T>::value, T> = 0
>
void fastor2d(){//...}
Note the = 0 at the end. That's simply a default value for the final template parameter, and it lets you get away with specifying T, M, K, and N but not the fifth parameter. The enable_if used here means that you can provide other templates called fastor2d, with their own sets of conditions.
First of all, I'll rewrite your function in a working form
template <typename T, size_t M, size_t K, size_t N,
std::enable_if_t<std::is_floating_point<T>::value, int> = 0>
void fastor2d() // ..........................................^^^ int, not T
{ }
The point is that I've changed the second template argument of std::enable_if_t form T to int.
I've also removed the typename before std::enable_if_t but isn't important: the typename is implicit in the _t at the end of std::enable_if_t, introduced from C++14. In C++11 the correct form is
// C++11 version
typename std::enable_if<std::is_floating_point<T>::value, int>::type = 0
// ^^^^^^^^ no _t ^^^^^^
But why it works?
Start from the name: SFINAE.
Is a short form for "Substitution Failure Is Not An Error".
It's a C++ rule so that when you write some thing as
template <int I, std::enable_if_t< I == 3, int> = 0>
void foo ()
{ }
and I is 3, the condition of std::enable_if_t is true so std::enable_if_t< I == 3, int> is substituted with int so foo() is enabled but when I isn't 3, the condition of std::enable_if_t if false so std::enable_if_t< I == 3, int> is not substituted so foo() isn't enabled but this ins't an error (if, through overloading, there is another foo() function, enabled, that matches the call, obviously).
So where is the problem in your code?
The problem is that std::enable_if_t is substituted, when the first template parameter is true, with the second parameter.
So if you write
std::enable_if_t<std::is_floating_point<T>::value, T> = 0
and you call
fastor2d<float, 0u, 1u, 2u>();
the std::is_floating_point<float>::value (but you can also use the shorter form std::is_floating_point_v<T> (_v and not ::value)) so the substitution take place and you get
float = 0
but, unfortunately, a template value (not type) parameter can't be of type floating point, so you get an error.
If you use int instead of T, the substitution give you
int = 0
and this is correct.
Another solution can be use the following form
typename = std::enable_if_t<std::is_floating_point<T>::value, T>
as suggested by Andreas Loanjoe, because the substitution give you
typename = float
that is a valid syntax.
But this solution has the drawback that doesn't works when you want to write two alternative functions, as in the following example
// the following solution doesn't works
template <typename T,
typename = std::enable_if_t<true == std::is_floating_point<T>::value, int>>
void foo ()
{ }
template <typename T,
typename = std::enable_if_t<false == std::is_floating_point<T>::value, int>>
void foo ()
{ }
where works the solution based on the value
// the following works
template <typename T,
std::enable_if_t<true == std::is_floating_point<T>::value, int> = 0>
void foo ()
{ }
template <typename T,
std::enable_if_t<false == std::is_floating_point<T>::value, int> = 0>
void foo ()
{ }
Using std::function, we can get the type of an argument using the argument_type, second_argument_type etc. typedefs, but I can't see a way to do the same thing with lambdas. Is it possible? (I'm using VS2010)
Say I want something like the following in my deserialization system used to read an object and pass it to a setter function:
template<typename F>
static void forward(F f)
{
// Create an object of the type of the first
// parameter to the function object F
typedef typename F::argument_type T;
T t;
//...do something with 't' here (deserialize in my case)
// Forward the object to the function
f(t);
}
It can be used like this and everything works fine:
std::function<void(int)> f = [](int i) -> void { setValue(i); };
forward(f);
But it will not work directly with lambdas:
forward([](int i) -> void { setValue(i); });
//error C2039: 'argument_type' : is not a
//member of '`anonymous-namespace'::<lambda1>'
Is there a way to access the parameter types in a way that will work for both lambdas and std::function objects? Maybe a way to get the std::function type of a lambda first, and then the argument_type from that?
Following on from the answer below, a version that works with lambdas and std::function is:
template<typename T, typename F>
static void forward(F f)
{
T t;
//...do something with 't' here (deserialize in my case)
f(t);
}
forward<int>([](int i) -> void { setValue(i); });
Since int is repeated here I was hoping to get rid of it - not so bad for int but more annoying for long-named types in a couple of namespaces. C'est la vie!
It's not desirable in the general case. (Note that it's quite easy for std::function<T(A)> to specify what e.g. argument_type is: it's just A! It's available in the type definition.)
It would be possible to require each and every function object type to specify its argument types, and in turn mandate that the closure types generated from lambda expression do so. In fact, pre-C++0x features like adaptable functors would only work for such types.
However, we're moving from that with C++0x and for good reasons. The simplest of which is simply overloading: a functor type with a templated operator() (a.k.a a polymorphic functor) simply takes all kind of arguments; so what should argument_type be? Another reason is that generic code (usually) attempts to specify the least constraints on the types and objects it operates on in order to more easily be (re)used.
In other words, generic code is not really interested that given Functor f, typename Functor::argument be int. It's much more interesting to know that f(0) is an acceptable expression. For this C++0x gives tools such as decltype and std::declval (conveniently packaging the two inside std::result_of).
The way I see it you have two choices: require that all functors passed to your template use a C++03-style convention of specifying an argument_type and the like; use the technique below; or redesign. I'd recommend the last option but it's your call since I don't know what your codebase looks like or what your requirements are.
For a monomorphic functor type (i.e. no overloading), it is possible to inspect the operator() member. This works for the closure types of lambda expressions.
So we declare these helpers
template<typename F, typename Ret, typename A, typename... Rest>
A
helper(Ret (F::*)(A, Rest...));
template<typename F, typename Ret, typename A, typename... Rest>
A
helper(Ret (F::*)(A, Rest...) const);
// volatile or lvalue/rvalue *this not required for lambdas (phew)
that accept a pointer to member function taking at least one argument. And now:
template<typename F>
struct first_argument {
typedef decltype( helper(&F::operator()) ) type;
};
[ an elaborate trait could successively query the lvalue-rvalue/const/volatile overloads and expose the first argument if it's the same for all overloads, or use std::common_type.]
#Luc's answer is great but I just came across a case where I also needed to deal with function pointers:
template<typename Ret, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...));
template<typename Ret, typename F, typename Arg, typename... Rest>
Arg first_argument_helper(Ret(F::*) (Arg, Rest...) const);
template <typename F>
decltype(first_argument_helper(&F::operator())) first_argument_helper(F);
template <typename T>
using first_argument = decltype(first_argument_helper(std::declval<T>()));
This can be used on both functors and function pointers:
void function(float);
struct functor {
void operator() (int);
};
int main() {
std::cout << std::is_same<first_argument<functor>, int>::value
<< ", "
<< std::is_same<first_argument<decltype(&function)>, int>::value
<< std::endl;
return 0;
}
Just wondering why is this invalid:
#include <iostream>
template <std::size_t... Is>
void foo(Is&&... args) {
std::cout << "foo called with " << sizeof...(Is) << "params\n";
}
int main() {
foo(1, 2, 3, 4);
}
It seems a perfectly reasonable example, yet it fails on any compiler I can get my hands on.
If I substitute size_t for class the example works as expected. I've also tried using the new auto template parameter but no online compiler accepts this so I don't know if this an invalid use case or a conformance issue.
It's not valid C++, that's why.
If you instantiate that function template with the template arguments 1, 2, 3, 4 then after substituting the arguments into the template you get the signature:
void foo(1&&, 2&&, 3&&, 4&&);
That's clearly not a valid function.
If you want to write a function template that accepts any number of arguments but only if they are of the right type, you can do that like this in C++17:
template<typename T>
using is_size_t = std::is_same<T, std::size_t>;
template<typename... T>
std::enable_if_t<std::conjunction<is_size_t<T>...>::value>>
foo(T&&... args);
Or alternatively (also using C++17):
template<typename... T>
std::enable_if_t<(std::is_same_v<std::size_t, T> && ...)>
foo(T&&... args);
For C++14 you need to implement std::conjunction yourself, e.g. using the and_ template from p0032r1
I've been working with another language lately and totally pulled a Monika there. Just to complement Jonathan's answer, (thanks for the explanation and the comments) this is how to ensure all parameters are of size_t type (what I was actually trying to do) using concepts:
template <class... Is>
requires (std::is_same<Is, int>::value && ...)
void foo(Is&&... args) { /*...*/ }
Or even (ma fav) by defining a dedicated concept
template <class T> concept bool Integer = std::is_same<T, int>::value;
template <Integer... Is> void foo(Is&&... args) { /*...*/ }
// ^^^^^^^awesome
Live
Can someone please explain to me why C++, at least to my knowledge, doesn't implement a strongly typed ellipsis function, something to the effect of:
void foo(double ...) {
// Do Something
}
Meaning that, in plain speak: 'The user can pass a variable number of terms to the foo function, however, all of the terms must be doubles'
There is
void foo(std::initializer_list<double> values);
// foo( {1.5, 3.14, 2.7} );
which is very close to that.
You could also use variadic templates but it gets more discursive. As for the actual reason I would say the effort to bring in that new syntax isn't probably worth it: how do you access the single elements? How do you know when to stop? What makes it better than, say, std::initializer_list?
C++ does have something even closer to that: non-type parameter packs.
template < non-type ... values>
like in
template <int ... Ints>
void foo()
{
for (int i : {Ints...} )
// do something with i
}
but the type of the non-type template parameter (uhm) has some restrictions: it cannot be double, for example.
Historically, the ellipsis syntax ... comes from C.
This complicated beast was used to power printf-like functions and is to be used with va_list, va_start etc...
As you noted, it is not typesafe; but then C is far from being typesafe, what with its implicit conversions from and to void* for any pointer types, its implicit truncation of integrals/floating point values, etc...
Because C++ was to be as close as possible as a superset of C, it inherited the ellipsis from C.
Since its inception, C++ practices evolved, and there has been a strong push toward stronger typing.
In C++11, this culminated in:
initializer lists, a short-hand syntax for a variable number of values of a given type: foo({1, 2, 3, 4, 5})
variadic templates, which are a beast of their own and allow writing a type-safe printf for example
Variadic templates actually reuse the ellipsis ... in their syntax, to denote packs of types or values and as an unpack operator:
void print(std::ostream&) {}
template <typename T, typename... Args>
void print(std::ostream& out, T const& t, Args const&... args) {
print(out << t, args...); // recursive, unless there are no args left
// (in that case, it calls the first overload
// instead of recursing.)
}
Note the 3 different uses of ...:
typename... to declare a variadic type
Args const&... to declare a pack of arguments
args... to unpack the pack in an expression
It is already possible with variadic templates and SFINAE :
template <bool...> struct bool_pack;
template <bool... v>
using all_true = std::is_same<bool_pack<true, v...>, bool_pack<v..., true>>;
template <class... Doubles, class = std::enable_if_t<
all_true<std::is_convertible<Doubles, double>{}...>{}
>>
void foo(Doubles... args) {}
Thanks to Columbo for the nice all_true trick. You will also be able to use a fold expression in C++17.
As later and upcoming standards are focusing on terser syntax (terse for-loops, implicit function templates...) it is very possible that your proposed syntax ends up in the Standard one day ;)
For why specifically such a thing wasn't proposed (or was proposed and rejected), I do not know. Such a thing would certainly be useful, but would add more complexity to the language. As Quentin demonstrates, there is already proposes a C++11 way of achieving such a thing with templates.
When Concepts gets added to the standard, we'll have another, more concise way:
template <Convertible<double>... Args>
void foo(Args... doubles);
or
template <typename... Args>
requires Convertible<Args, double>()...
void foo(Args... doubles);
or, as #dyp points out:
void foo(Convertible<double>... doubles);
Personally, between the current solution and the ones that we will get with Concepts, I feel that's an adequate solution to the problem. Especially since the last one is basically what you'd originally asked for anyway.
The way to achieve (sort of) what you suggest is to use variadic templates
template<typename... Arguments>
void foo(Arguments... parameters);
however you can pass any type in the parameter pack now.
What you propose has never been implemented, maybe it could be a great addition to the language, or it could just be too difficult to implement as things stand. You could always try to write a proposal and submit it to isocpp.org
template<typename T, typename... Arguments>
struct are_same;
template <typename T, typename A1, typename... Args>
struct are_same<T, A1, Args...>{ static const bool value = std::is_same<T, A1>::value && are_same<T, Args...>::value;};
template <typename T>
struct are_same<T>{static const bool value = true;};
template<typename T, typename... Arguments>
using requires_same = std::enable_if_t<are_same<T, Arguments...>::value>;
template <typename... Arguments, typename = requires_same<double, Arguments...>>
void foo(Arguments ... parameters)
{
}
Based on Matthew's answer:
void foo () {}
template <typename... Rest>
void foo (double arg, Rest... rest)
{
/* do something with arg */
foo(rest...);
}
If the code using foo compiles, you know all the arguments are convertible to double.
Because you can use
void foo(std::vector<T> values);
I have a function which takes one parameter with a default value. Now I also want it to take a variable number of parameters and forward them to some other function. Function parameters with default value have to be last, so... can I put that parameter after the variadic pack and the compiler will detect whether I'm supplying it or not when calling the function?
(Assuming the pack doesn't contain the type of that one last parameter. If necessary, we can assume that, because that type is generally not supposed to be known to the user, otherwise it's considered as wrong usage of my interface anyway....)
template <class... Args>
void func (Args&&... args, SomeSpecialType num = fromNum(5))
{
}
No, packs must be last.
But you can fake it. You can detect what the last type in a pack is. If it is SomeSpecialType, you can run your func. If it isn't SomeSpecialType, you can recursively call yourself with your arguments forwarded and fromNum(5) appended.
If you want to be fancy, this check can be done at compile time (ie, a different overload) using SFINAE techniques. But that probably isn't worth the hassle, considering that the "run-time" check will be constant on a given overload, and hence will almost certainly be optimized out, and SFINAE shouldn't be used lightly.
This doesn't give you the signature you want, but it gives you the behavior you want. You'll have to explain the intended signature in comments.
Something like this, after you remove typos and the like:
// extract the last type in a pack. The last type in a pack with no elements is
// not a type:
template<typename... Ts>
struct last_type {};
template<typename T0>
struct last_type<T0> {
typedef T0 type;
};
template<typename T0, typename T1, typename... Ts>
struct last_type<T0, T1, Ts...>:last_type<T1, Ts...> {};
// using aliases, because typename spam sucks:
template<typename Ts...>
using LastType = typename last_type<Ts...>::type;
template<bool b, typename T=void>
using EnableIf = typename std::enable_if<b, T>::type;
template<typename T>
using Decay = typename std::decay<T>::type;
// the case where the last argument is SomeSpecialType:
template<
typename... Args,
typename=EnableIf<
std::is_same<
Decay<LastType<Args...>>,
SomeSpecialType
>::value
>
void func( Args&&... args ) {
// code
}
// the case where there is no SomeSpecialType last:
template<
typename... Args,
typename=EnableIf<
!std::is_same<
typename std::decay<LastType<Args...>>::type,
SomeSpecialType
>::value
>
void func( Args&&... args ) {
func( std::forward<Args>(args)..., std::move(static_cast<SomeSpecialType>(fromNum(5))) );
}
// the 0-arg case, because both of the above require that there be an actual
// last type:
void func() {
func( std::move(static_cast<SomeSpecialType>(fromNum(5))) );
}
or something much like that.
Another approach would be to pass variadic arguments through a tuple.
template <class... Args>
void func (std::tuple<Args...> t, SomeSpecialType num = fromNum(5))
{
// don't forget to move t when you use it for the last time
}
Pros : interface is much simpler, overloading and adding default valued arguments is quite easy.
Cons : caller has to manually wrap arguments in a std::make_tuple or std::forward_as_tuple call. Also, you'll probably have to resort to std::index_sequence tricks to implement the function.
Since C++17 there is way to work around this limitation, by using class template argument deduction and user-defined deduction guides.
This is espactialy useful for C++20 std::source_location.
Here is C++17 demo:
#include <iostream>
int defaultValueGenerator()
{
static int c = 0;
return ++c;
}
template <typename... Ts>
struct debug
{
debug(Ts&&... ts, int c = defaultValueGenerator())
{
std::cout << c << " : ";
((std::cout << std::forward<Ts>(ts) << " "), ...);
std::cout << std::endl;
}
};
template <typename... Ts>
debug(Ts&&...args) -> debug<Ts...>;
void test()
{
debug();
debug(9);
debug<>(9);
}
int main()
{
debug(5, 'A', 3.14f, "foo");
test();
debug("bar", 123, 2.72);
}
Live demo
Demo with source_location (should be available since C++20, but still for compilers it is experimental).
This is coming a bit late, but in C++17 you can do it with std::tuple and it would be quite nice overall. This is an expansion to #xavlours 's answer:
template <class... Args>
void func (std::tuple<Args&&...> t, SomeSpecialType num = fromNum(5))
{
// std::apply from C++17 allows you to iterate over the tuple with ease
// this just prints them one by one, you want to do other operations i presume
std::apply([](auto&&... args) {((std::cout << args << '\n'), ...);}, t);
}
Then, make a simple function to prepare them:
template<typename... Args>
std::tuple<Args&&...> MULTI_ARGS(Args&&... args) {
return std::tuple<Args&&...>(args...);
}
Now you can call the function like this:
func(MULTI_ARGS(str1, int1, str2, str3, int3)); // default parameter used
func(MULTI_ARGS(str1, int1, str2)); // default parameter used
func(MULTI_ARGS(str1, int1, str2, str3, int3, otherStuff), fromNum(10)); // custom value instead of default
Disclaimer: I came across this question as I was designing a logger and wanted to have a default parameter which contains std::source_location::current() and as far as I was able to find, this is the only way that ensures the caller's information is passed accurately. Making a function wrapper will change the source_location information to represent the wrapper instead of the original caller.