将带有默认值的函数作为参数传递并忽略它们

3

我需要将表示 T 向量的字符串转换为相应的向量。

我的问题是,我想传递一个简单的参数:转换函数。这里是 split

template <class T>
auto split(const std::string &s, const std::function<T(const std::string&)> &convert, char sep = ',') -> std::vector<T>
{
    std::stringstream ss(s);
    std::vector<T> result;

    while (ss.good())
    {
        std::string substr;
        std::getline(ss, substr, sep);
        if (!substr.empty())
            result.push_back(convert(substr));
    }
    return result;
};

当传递标准函数,例如std::stoi时,由于std::stoi的默认参数,编译会失败。因为它的签名是int stoi(const string& __str, size_t* __idx = 0, int __base = 10);

auto q = split<int>(subs, std::stoi);

error: no matching function for call to 'split'
            auto q = split<int>(subs, std::stoi);
                     ^~~~~~~~~~

显然,我可以通过使用lambda函数来欺骗编译器:

auto q = split<std::size_t>(subs, [](const std::string &s){ return std::stoul(s); });

有没有元编程的技巧可以让我以某种方式 忽略 默认参数?


默认参数是什么意思?你明确指定了要使用 split<int> - nwp
我的意思是,实际上std::stoi有默认参数:签名为int stoi(const string& __str, size_t* __idx = 0, int __base = 10);。我希望忽略这个默认签名。 - senseiwa
如果你能避免使用std::function,那会让你的生活更轻松。(最好使用一个模板化的函数参数。) - alfC
2个回答

5

编辑:在这种情况下,它实际上没有帮助。我保留它是因为在某些其他情况下它很有用,例如如果您有一个返回可以转换为T的内容的函数,但它并不解决stoi的任何问题。


不要显式指定函数的类型。让convert成为任何类型;如果您尝试传递不能在std :: string上调用或不返回可转换为T的内容,则会出现错误。除非您特别有理由需要具体类型,否则不需要限制类型。在这种情况下,您没有必要这样做。

因此,您可以将函数声明为

template <class T, class F>
auto split(const std::string &s, const F&& convert, char sep = ',') -> std::vector<T>

@Yakk 嗯,对,重载。我觉得 SFINAE 真的无法处理这个问题,所以我不知道是否可能在调用站点透明地工作而没有宏的情况下使其正常工作,但我可能是错的。 - Daniel H
没有重载。如果没有重载,传入的函数指针或引用(必须解析为对象才能传入)将不会携带默认参数。因此,在调用点它将无法工作。 - Yakk - Adam Nevraumont
@Yakk 你说得对,我的回答在某些情况下有帮助,但在这种情况下不适用。 - Daniel H

4
#define RETURNS(...) \
  noexcept(noexcept(__VA_ARGS__)) \
  -> decltype( __VA_ARGS__ ) \
  { return __VA_ARGS__; }

#define OVERLOADS_OF(...) \
  [](auto&&...args) \
  RETURNS( __VA_ARGS__( decltype(args)(args)... )

这个宏允许你获取一个函数的名称,并生成包含其重载函数的lambda表达式。
auto q = split<std::size_t>( subs, OVERLOADS_OF(std::stroul) );

这很好而且简洁。

默认参数只能通过在函数的实际名称上调用()来访问,将名称“移动”到不同的上下文中的唯一方法是将其作为文本放入lambda中。

顺便说一句,@barry提出了一个提案,用=> X替换RETURNS(X)。 我不知道目前是否有维护此提案以替换OVERLOADS_OF宏(以前有过)。

可能反射提案将允许您访问函数名称的默认参数和重载集,并且高级元编程将使您能够生成没有宏的OVERLOADS_OF


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接