使用默认值作为参数传递函数忽略它们

时间:2017-10-05 14:05:00

标签: c++ c++11 templates

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

我的问题是我想传递一个简单的参数:转换器功能。这是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); });

是否有元编程技巧允许我以某种方式忽略默认参数?

2 个答案:

答案 0 :(得分: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>

答案 1 :(得分: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) );

这很简洁。

默认参数只能通过在函数的实际名称上调用()来访问,并且只能通过&#34;移动名称&#34;进入一个不同的上下文是将它作为文本填充到lambda中。

顺便说一句,@ barry提出提案,将RETURNS(X)替换为=> X lambdas。我不知道目前维护的建议是替换OVERLOADS_OF宏(有一段时间了)。

反映提议可能允许您访问函数名称的默认参数和重载集,然后花哨的元编程可以让您生成OVERLOADS_OF而无需宏。