Specifying one type for all arguments passed to variadic function or variadic template function w/out using array, vector, structs, etc?

You can just accept the arguments by the variadic template and let typechecking check the validity later on when they are converted.

You can check convertibility on the function interface level though, to make use of overload resolution for rejecting outright wrong arguments for example, by using SFINAE

template<typename R, typename...> struct fst { typedef R type; };

template<typename ...Args>
typename fst<void, 
  typename enable_if<
    is_convertible<Args, ToType>::value
  >::type...
>::type 
f(Args...);

For your use-case if you know the steps to go from an std::array<> to your dragon_list_t then you have already solved it though according to the first option above ("convert-later"):

template<typename ...Items>
dragon_list_t make_dragon_list(Items... maidens) {
    std::array<Maiden, sizeof...(Items)> arr = {{ maidens ... }};
    // here be dragons
}

If you combine this with the above is_convertible approach you have a reject-early template that also does overload resolution on arguments and rejects them if not applicable.


If you don't use template on the parameter not in the pack the variadic function will resolve to have all arguments of the same type.

Here's an example for an extended max function that only accepts ints (or types convertible to int).

int maximum(int n) // last argument must be an `int`
{
    return n;
}

template<typename... Args>
int maximum(int n, Args... args) // first argument must be an int
{
    return std::max(n, maximum(args...));
}

Explanation: When you unpack the argument pack (args...) the compiler looks for the best overload. If the pack had only one parameter then the best candidate is maximum(int) so the only parameter must be and of type int (or convertible to int). If there are more than one elements in the pack then the only candidate is maximum(int, typename...) so the first argument must be of type int (or convertible to int). It's simple to prove by induction that all the types in the pack must be of a type convertible to int).


Since you've included the C++0x tag, the obvious answer would be to look up initializer lists. An initializer list lets you specify a number of arguments to a ctor that will be automatically converted to a single data structure for processing by the ctor.

Their primary (exclusive?) use is for exactly the sort of situation you've mentioned, passing a number of arguments of the same type to use in creating some sort of list/array/other collection of objects. It'll be supported by (for one example) std::vector, so you could use something like:

std::vector<dragon> dragons_to_slay{Eunice, Helga, Aida};

to create a vector of three dragon objects. Most (all?) of the other collections will include the same, so if you really insist on a list of dragons you should be able to get that pretty easily as well.