Problems with last recursion in metaprogramming
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);
};
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);
};
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.
精彩评论