0

I have the following (partial) code in a class where I try to evaluate a value against a list of values via metaprogramming in C++11.

bool eval(GLenum value)
{
    return false;
};

template<GLenum One, GLenum... Others>
bool eval(GLenum value)
{
    if( value == One )
        return true;

    // Try out the rest
    return eval<Others...>(value);
};

gcc complains:

../emul/GLPart.h: In member function ‘bool GLPart::eval(GLenum) [with unsigned int One = 519u, unsigned int ...Others = {}, unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’: ../emul/GLPart.h:26:31: instantiated from ‘bool GLPart::eval(GLenum) [with unsigned int One = 518u, unsigned int ...Others = {519u}, unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’ ../emul/GLPart.h:26:31: instantiated from ‘bool GLPart::eval(GLenum) [with unsigned int One = 517u, unsigned int ...Others = {518u, 519u}, unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’ ../emul/GLPart.h:26:31: instantiated from ‘bool GLPart::eval(GLenum) [with unsigned int One = 516u, unsigned int ...Others = {517u, 518u, 519u}, unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’ ../emul/GLPart.h:26:31: instantiated from ‘bool GLPart::eval(GLenum) [with unsigned int One = 515u, unsigned int ...Others = {516u, 517u, 518u, 519u}, unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’ ../emul/GLPart.h:26:31: instantiated from ‘bool GLPart::eval(GLenum) [with unsigned int One = 514u, unsigned int ...Others = {515u, 516u, 517u, 518u, 519u}, unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’ ../emul/GLPart.h:26:31: instantiated from ‘bool GLPart::eval(GLenum) [with unsigned int One = 513u, unsigned int ...Others = {514u, 515u, 516u, 517u, 518u, 519u}, unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’ ../emul/GLPart.h:26:31:
instantiated from ‘bool GLPart::eval(GLenum) [with unsigned int One = 512u, unsigned int ...Others = {513u, 514u, 515u, 516u, 517u, 518u, 519u}, unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’ ../emul/GLPart.h:31:43: instantiated from ‘bool GLPart::Evaluate(GLenum) [with unsigned int ...ValidEnums = {512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u}, GLenum = unsigned int]’ alpha.cpp:8:7: instantiated from here ../emul/GLPart.h:26:31: error: no matching function for call to ‘GLPart<512u, 513u, 514u, 515u, 516u, 517u, 518u, 519u>::eval(GLenum&)’

So it seems like it chokes on the last recursion when One has a value and Others don't. In this case the template parameters should then be empty. Do I need to declare the ordinary eval in another way? Haven't coded C++ in a while so it may be trivial but I just don't get it ;)

When trying to add template<> to the first eval it chokes:

../emul/GLPart.h:14:11: error: explicit specialization in non-namespace scope ‘class GLPart’ ../emul/GLPart.h:21:7: error: too many template-parameter-lists ../emul/GLPart.h: In member function ‘bool GLPart::Evaluate(GLenum)’: ../emul/GLPart.h:32:23: error: parameter packs not expanded with ‘...’: ../emul/GLPart.h:32:23: note: ‘ValidEnums’ ../emul/GLPart.h:32:33: error: expected ‘,’ or ‘;’ before ‘...’ token

Solution:

template<GLenum One>
bool eval(GLenum value)
{
    return value == One;
};

template<GLenum One, GLenum Two, GLenum... Others>
bool eval(GLenum value)
{
    if( eval<One>(value) )
        return true;

    // Try out the rest
    return eval<Two, Others...>(value);
};
abergmeier
  • 13,224
  • 13
  • 64
  • 120
  • 1
    possible duplicate of [What's the essential difference between these two variadic functions?](http://stackoverflow.com/questions/7111089/whats-the-essential-difference-between-these-two-variadic-functions) – Bo Persson Aug 20 '11 at 19:11
  • 4
    The first function is not a template, so it can never be called like this `eval(value);`. – Bo Persson Aug 20 '11 at 19:12
  • Tried and did create another error... – abergmeier Aug 20 '11 at 19:30

2 Answers2

3

As Bo Persson said, said, the first one is not a template, so calling eval will never call the first version. You want:

template<>  //this tells compiler that eval is a template function
bool eval(GLenum value)
{
    return false;
};
template<GLenum One, GLenum... Others>
bool eval(GLenum value)
{
    if( value == One )
        return true;

    // Try out the rest
    return eval<Others...>(value);
};
Mooing Duck
  • 64,318
  • 19
  • 100
  • 158
  • I don't think you can do this either. The problem is that you cannot specialize function templates, just class templates. It might have worked if the call was `eval(value)`, but not `eval(value)`. – Bo Persson Aug 20 '11 at 19:58
  • Interestingly this was a example from Wikipedia :) http://en.wikipedia.org/wiki/C%2B%2B0x#Variadic_templates – abergmeier Aug 20 '11 at 20:17
  • But Wikipedia has type arguments (not value arguments), so the calls rely on argument type deduction for overload resolution. – UncleBens Aug 20 '11 at 20:25
2

Since this tends to produce lots of ambiguity errors, the variation that seems to work unambigously looks like this:

template<GLenum One> 
bool eval(GLenum value)
{
    return value == One;
};
template<GLenum One, GLenum Two, GLenum... Others>
bool eval(GLenum value)
{
    if( value == One )
        return true;

    // Try out the rest
    return eval<Two, Others...>(value);
};

The first overload takes exactly one argument, the second at least two. Taking zero arguments probably doesn't make sense anyway.

UncleBens
  • 40,819
  • 6
  • 57
  • 90
  • This works indeed. It prevents very elegantly _specializing function templates_ problem mentioned by Bo Persson. – abergmeier Aug 20 '11 at 20:56