views:

85

answers:

4

First of all, the code:

template<typename Func, typename Func2>
void ForEachField(Func normalHandler, Func2 arrayHandler = NULL, bool skipUnknowns = true)
{
    for(int i = 0; i < mFields.size(); ++i)
    {
        Field *f = mFields[i];

        if(skipUnknowns && f->IsUnknown())
            continue;

        if(f->GetCount() == 1 || !arrayHandler)
            normalHandler(f);
        else
            arrayHandler(f);
    }
}

And an example of usage:

df->ForEachField(
    [&](Field *field) { f << "\t" << format("public $%s;\n") % field->GetName(); },
    [&](Field *field) { f << "\t" << format("public $%s;\n") % field->GetName() % field->GetSize(); }
); // Works

df->ForEachField(
    [&](Field *field) { WriteLine(f, format("\t\t'%s' => array('type' => '%s'),") % field->GetName() % field->GetTypeInfo()->Name);
}); // Doesn't work

The second call doesn't work because it says:

OutputPhp.cpp(27): error C2783: 'void DataFile::ForEachField(Func,Func2,bool)' : could not deduce template argument for 'Func2' see declaration of 'DataFile::ForEachField'

Is there any way I can make the second parameter optional, while still using templates, and while not having to manually specify the second template argument?

A: 

Since you're using C++0x features already (lambdas), just use another one: default template arguments

template<typename Func, typename Func2 = void*>
void ForEachField(Func normalHandler, Func2 arrayHandler = NULL, bool skipUnknowns = true)
Tyler McHenry
It doesn't seem to work: `error C4519: default template arguments are only allowed on a class template`
Andreas Bonini
Must be a difference between g++ and MSVC++. It works on g++.
Tyler McHenry
Yup, MSVC doesn't support that yet. (And since both compilers are missing support for major parts of C++0x, it's a bit optimistic to say "just use another C++0x feature":))
jalf
+3  A: 

You could add an overload for ForEachField:

template<typename Func>
void ForEachField (Func normalHandler)
{
    ForEachField<Func, void *>(normalHandler, NULL, true);
}
jon hanson
This is actually a great idea. Obviously it should be `ForEachField<Func, void *>` or I will run into the same problem ;) But now I ran into another problem.. !arrayHandler if arrayHandler is a lambda doesn't work, trying to find a solution now :O
Andreas Bonini
Ok, well the original version did compile though i didn't run it.
jon hanson
A: 

What about making the second parameter non-default, and creating an overloaded wrapper method that takes a single typename Func parameter.

Mark B
A: 

I know that code duplication is usually regarded as "bad", however in this case I would probably NOT use a runtime check to detect whether or not I passed an argument... whenever the check can be done at compile time...

template<typename Func, typename Func2>
void ForEachField(Func normalHandler, Func2 arrayHandler, bool skipUnknowns = true)
{
    for(int i = 0; i < mFields.size(); ++i)
    {
        Field *f = mFields[i];

        if(skipUnknowns && f->IsUnknown()) { continue; }

        if(f->GetCount() == 1) { normalHandler(f); }
        else { arrayHandler(f); }
    }
}


template<typename Func>
void ForEachField(Func normalHandler, bool skipUnknowns = true)
{
    for(int i = 0; i < mFields.size(); ++i)
    {
        Field *f = mFields[i];

        if(skipUnknowns && f->IsUnknown()) { continue; }

        if(f->GetCount() == 1) { normalHandler(f); }
    }
}

Remember that you can perfectly overload functions templates as usual.

This will in turn solve the two problems:

  • Second parameter is now optional (for all intents and purposes)
  • No more application of operator! on a lambda (which does not work)
Matthieu M.