struct A { A(int){} };
template <A... ARGS> void function(ARGS... args) {}
function(A(3), A(2), A(5)); // should be ok
struct B { B(int){} };
function(A(4), B(3), A(1)); // should be an error
Is there a way to accomplish this with variadic templates?
Regards,
Rodolfo Lima
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
You can extend the is_same test from <type_traits> to work for the
variadic arguments:
// same types?
template<class, class ...> // not defined
struct SameTypes;
template<class ValueT>
struct SameTypes<ValueT> : true_type
{ };
template<class FirstT, class SecondT, class ... ArgTypes>
struct SameTypes<FirstT, SecondT, ArgTypes...>
: public std::integral_constant<bool,
std::is_same<FirstT, SecondT>::value &&
SameTypes<FirstT, ArgTypes...>::value >
{ };
Then you can use a
std::enable_if<SameTypes<ARGS...>::value>
to guard your function.
Bo Persson
In C++0x, you would use a SameType concept to indicate that all
typenames in Args are A.
template <typename... Args>
void function(Args... args)
requires SameType<A, Args>...
{
That's a good solution, thank you. But I get the feeling that somehow
variadic templates' syntax should be extended to cope with this use
case, what do you think? Is this common enough?
Regards,
Rodolfo Lima
Not sure about variadrics alone, but if you combine them with
concepts, it's definitely possible.
Something like this:
template <typename... Args>
requires SameType<A, Args>...
void fn(Args args)
{
If you use variadic expansion for concept requirements (as in my
previous post) rather than writing your own helper, it's not really
that cumbersome. And the current concepts draft does include variadic
expansions for "requires".
When we will have concepts in C++, all this could be written as:
template <class... ARGS>
requires SameType<A, ARGS>...
void function(ARGS... args) {}
HTH,
Ganesh
Yes, there's this quite new world of concepts in c++ opening, at least
for me. Maybe it's possible to create a concept in a way that my
original syntax would work, isn't it? Something like
template <SameType... ARGS> void function(ARGS... args) {}
Although the 'requires' version that you and Pavel came up is clearer,
IMHO. Let's wait till conceptgcc gets merged with gcc.
Regards,
Rodolfo Lima.
template<SameType<auto, A>... ARGS> void f(ARGS... args) {}
is the current syntax, I think.
If you don't care what the type is, so long as it's the same type for
all the parameters, try
template<typename A, SameType<auto, A>... ARGS>
void f(A arg1, ARGS... args) {}
That does mean the function will have to have at least one parameter.
Alternatively, use std::initializer_list:
template<typename A>
void f(std::initializer_list<A> args) {}
The function will have to be called with braces:
f({1,2,3});
I'm not sure if you can have an initializer list with no parameters,
but here you certainly can't because there'd be nothing to deduce A
from.
Yechezkel Mett
The currently proposed wording for concepts already provides a syntax
which does precisely that, it is:
template <SameType<auto, A>... Args>
void function(Args... args);
>
> Although the 'requires' version that you and Pavel came up is clearer,
> IMHO.
>
I definitely agree. While this:
template <MyConcept T> /* ... */;
is definitely an improvement over the perfectly equivalent syntax:
template <typename T> requires MyConcept<T> /* ... */;
I can't say the same for non-unary concepts, where the use of the auto
keyword as a placeholder looks like a hack and makes the template almost
unreadable. Moreover, the syntax only works when auto is in the first
place, so this:
template <SameType<A, auto>... Args> // illegal!
void function(Args... args);
is illegal. This can be a problem with non-symmetric binary concepts
such as DerivedFrom or Convertible.
I wonder if we really needed such syntax...
Ganesh