【问题标题】:What to do with template typenames for optional arguments?如何处理可选参数的模板类型名?
【发布时间】:2010-07-07 20:28:34
【问题描述】:

首先是代码:

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);
    }
}

还有一个用法示例:

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

第二次调用不起作用,因为它说:

OutputPhp.cpp(27): 错误 C2783: 'void 数据文件::ForEachField(Func,Func2,bool)' : 无法推断模板参数 对于 'Func2' 参见“DataFile::ForEachField”的声明

有什么方法可以让第二个参数成为可选参数,同时仍然使用模板,而不必手动指定第二个模板参数?

【问题讨论】:

    标签: c++ templates lambda c++11


    【解决方案1】:

    您可以为ForEachField 添加重载:

    template<typename Func>
    void ForEachField (Func normalHandler)
    {
        ForEachField<Func, void *>(normalHandler, NULL, true);
    }
    

    【讨论】:

    • 这其实是个好主意。显然它应该是ForEachField&lt;Func, void *&gt; 否则我会遇到同样的问题;) 但现在我遇到了另一个问题.. !arrayHandler 如果 arrayHandler 是 lambda 不起作用,现在试图找到解决方案:O
    • 好的,虽然我没有运行原始版本,但它确实编译了。
    【解决方案2】:

    我知道代码重复通常被认为是“坏的”,但是在这种情况下,我可能不会使用运行时检查来检测我是否传递了参数......只要检查可以在编译时完成。 ..

    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); }
        }
    }
    

    请记住,您可以像往常一样完美地重载函数模板。

    这将反过来解决两个问题:

    • 第二个参数现在是可选的(用于所有意图和目的)
    • 不再在 lambda 上应用 operator!(这不起作用)

    【讨论】:

      【解决方案3】:

      由于您已经在使用 C++0x 功能(lambdas),只需使用另一个功能:默认模板参数

      template<typename Func, typename Func2 = void*>
      void ForEachField(Func normalHandler, Func2 arrayHandler = NULL, bool skipUnknowns = true)
      

      【讨论】:

      • 它似乎不起作用:error C4519: default template arguments are only allowed on a class template
      • 必须是 g++ 和 MSVC++ 的区别。它适用于 g++。
      • 是的,MSVC 还不支持。 (而且由于两个编译器都缺少对 C++0x 主要部分的支持,所以说“只使用另一个 C++0x 特性”有点乐观:))
      【解决方案4】:

      如何将第二个参数设为非默认参数,并创建一个采用单个 typename Func 参数的重载包装方法。

      【讨论】:

        猜你喜欢
        • 2019-12-12
        • 2021-03-08
        • 2019-09-01
        • 2017-03-18
        • 2015-08-07
        • 1970-01-01
        • 2014-01-29
        • 1970-01-01
        • 2021-11-18
        相关资源
        最近更新 更多