9

Related:


Consider this pair of variadic templates:

template<typename Dummy>
bool All(Param& c) {
    return true;
}

template<typename Dummy, Func* f, Func* ...rest>
bool All(Param& c) {
    return f(c) && All<Dummy, rest...>(c);
}

This works and compiles. However, how to write it without the first template parameter?

Sounds trivial? Well, that's what I thought. :-) Let's consider some ideas.

Idea #1:

template<Func* f, Func* ...rest>
bool All(Param& c) {
    return f(c) && All<rest...>(c);
}
template<>
bool All(Param& c) {
    return true;
}

Won't work... When I attempted this I had specialization in mind, but on the second thought that's not how it works.

In the original example I created two different templates of overloads, first taking 1 template parameter and second taking 2 or more. No ambiguities and no specialization involved. am I getting it right?

Idea #2:

bool All(Param& c) {
    return true;
}

template<Func* f, Func* ...rest>
bool All(Param& c) {
    return f(c) && All<rest...>(c);
}

Won't work obviously, All<rest...> with rest... being empty won't expand to a call to a non-template function.

Idea #3:

Let's rebuild the solution a bit.

template<Func* f>
bool All(Param& c) {
    return f(c);
}

template<Func* f, Func* ...rest>
bool All(Param& c) {
    return f(c) && All<rest...>(c);
}

This one is a no-go, because All(c) would be ambiguous. Hence I need to have a 0-arg case and a >0-arg case... Or what about a 1-arg case and a >1-arg case?

Idea #3.5:

template<Func* f>
bool All(Param& c) {
    return f(c);
}

template<Func* f, Func* f2, Func* ...rest>
bool All(Param& c) {
    return f(c) && All<f2, rest...>(c);
}

Yup, works, but contains copypasta (simple in this case but might be bigger!), hence I'd say it's no better than what I've started with. Just another workaround.

Idea #4:

Let's try #1 but with classes instead of functions.

template<Func* f, Func* ...rest>
struct All {
    static bool func(Param& c) {
        return f(c) && All<rest...>(c);
    }
};
template<>
struct All {
    static bool func(Param& c) {
        return true;
    }
};

This looks promising since I can specialize classes. But hey, what is it?

sorry, unimplemented: cannot expand 'rest ...' into a fixed-length argument list

Wasn't this a GCC 4.4 thing? I'm on MinGW GCC 4.6.1 (tdm-1).


Anyway, should I think that I cannot do such an elementary thing in a straightforward way? Is it required to use the workaround with an additional dummy template parameter to accomplish this task?

Or is there a simple, correct variant to specify the zero-argument case, which would work?

Community
  • 1
  • 1
Kos
  • 70,399
  • 25
  • 169
  • 233
  • 1
    All of your subsequent ideas also have two classes/overloads/specializations.. What are you attempting to gain here? – ildjarn Nov 01 '11 at 23:00
  • 1
    Your Idea #3.5 has my vote. It is what I would've put in an answer if you hadn't written it up yourself. And if I'm not mistaken, there is some debate as to whether #3 is ambiguous or not. I'm not sure where the dust settled on that one, or if it has even settled yet. And it is because of that dust I prefer to just side-step the ambiguity issue and go with #3.5. – Howard Hinnant Nov 01 '11 at 23:49
  • 1
    What Howard said. +1 for the effort put into the question – sehe Nov 01 '11 at 23:54
  • @Kos: I might misunderstand the question though, does [this](http://ideone.com/DpzNA) meet the objective? – Ise Wisteria Nov 02 '11 at 09:32
  • @IseWisteria, that's exactly what I've been looking for; please post as answer so that you can be credited. – Kos Nov 02 '11 at 14:49
  • @Kos: Thanks! Please allow me a minute to write. – Ise Wisteria Nov 02 '11 at 18:25

2 Answers2

3

In this question's case, since template parameters are non-type, if we prepare a function with default template argument like the following, Dummy parameter can be saved:

template<typename = void>
bool All(Param& c) {
    return true;
}

template<Func* f, Func* ...rest>
bool All(Param& c) {
    return f(c) && All<rest...>(c);
}

However, I'm not sure this is always applicable. For more general case, std::enable_if or similar dispatch might be needed (this will make the code a little lengthy though).

Ise Wisteria
  • 11,259
  • 2
  • 43
  • 26
1

Looks like your question is similar to this one: Compilation Error on Recursive Variadic Template Function

There are two answers there that should work; one that is your #3.5 and the second is one you didnt have.

Community
  • 1
  • 1
Jared Grubb
  • 1,139
  • 9
  • 17