2

I am trying to create a function named Choose which can take the following as arguments:

template<typename... Args>
class Option
{
    Option(Args... arguments)
    {
        // irrelevant
    }
    // ...
}

void Foo()
{
    Choose(
         Option<int, int>(3, 5),
         Option<int>(7,123),
         Option<int, int, int, int>(1, 2, 3, 4)
    );
}

So I have a class with variadic types, and I want to create a function that takes any number of instances of that class, of which every instance can have different arguments for its types.

I was able to create such a function, where all instances need to have the same arguments for their types:

template <template <typename... Args> class... Opt, typename... Args>
void Choose(EnemyAIState& state, Opt<Args...>... option)
{
    // irrelevant
}

void Foo()
{
    Choose(state,
        Option<int>(1),
        Option<int>(2),
        Option<int>(3)
    );
}

However, I am unable to achieve my final goal, as I cannot find the right syntax to use. I am hoping you can help me in the right direction.

Aart Stuurman
  • 3,188
  • 4
  • 26
  • 44
  • 1
    You can always take them as simply `template void Choose(EnemyAIState& state, Opt... option)`. – T.C. Aug 21 '14 at 01:30
  • Oh wow haha, fresh thoughts are always better. Now that it works, I'm still interested in if this is possible at all. – Aart Stuurman Aug 21 '14 at 01:33
  • By which I mean in the way I started it. – Aart Stuurman Aug 21 '14 at 01:33
  • I don't think that's possible. If you want better error messages, use a `static_assert`. – T.C. Aug 21 '14 at 02:09
  • @AartStuurman: Answers do NOT go in questions. If your "answer" is different than T.C.'s answer, post that as a new answer on this page please. – Mooing Duck Aug 22 '14 at 00:03
  • If your answer is merely an _extension_ of his, you could alternatively post a link to the code in a comment on his answer and suggest that he update his answer. But posting it as a new answer is still acceptable. – Mooing Duck Aug 22 '14 at 00:09
  • I've removed the code from my question, and posted a link to the question where a already clear explanation was given for it, instead, at T.C.s answer. – Aart Stuurman Aug 22 '14 at 09:54

2 Answers2

2

I don't think you can do what you are trying to do directly - you'd need something like a "pack of packs", and there's no such thing.

If you want better error messages, write a static_assert that tests that each of the types passed in is an Option:

// helper template that checks all of values are true
template<bool... values>
struct all_true;

template<>
struct all_true<> : std::true_type { };

template<bool b, bool...values>
struct all_true<b, values...> : std::integral_constant<bool, b && all_true<values...>::value> { };

template<typename... Args>
struct Option
{
    Option(Args... /*arguments*/)
    {
        // irrelevant
    }
    // ...
};

// trait class that tests that a type is an Option
template<typename T>
struct is_option : std::false_type { };

template<typename... Args>
struct is_option<Option<Args...>> : std::true_type { };

template <typename... Opt>
void Choose(Opt... arguments)
{
    // check that each type is an Option
    static_assert(all_true<is_option<Opt>::value...>::value, "Arguments must all be Options");
    // irrelevant
}

Demo.

T.C.
  • 133,968
  • 17
  • 288
  • 421
  • That's pretty cool. I didn't know about assertion in C++ at all. Thanks a lot, this gives some clear messages. – Aart Stuurman Aug 21 '14 at 10:59
  • The following link provides a generic version of your is_option function, which might be useful for people reading this question: http://stackoverflow.com/questions/17390605/doing-a-static-assert-that-a-template-type-is-another-template. – Aart Stuurman Aug 22 '14 at 09:52
1

If processing the parameters one at a time, the standard variadic template solution works well:

void Choose()
{
    //do nothing, end of list
}

template <typename... Args, class... Rest>
void Choose(const Option<Args...>& option, Rest&&... rest)
{
    //irrelevant

    Choose(std::forward<Rest>(rest)...);
}

It gives the same error message you'd get the other way, just in a more intimidating callstack size. This is how most variadic template functions work that I've seen: quasi-recursion.

http://ideone.com/XuWSSx

Mooing Duck
  • 64,318
  • 19
  • 100
  • 158