我需要将表示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); });
是否有元编程技巧允许我以某种方式忽略默认参数?
答案 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提出c++2a提案,将RETURNS(X)
替换为=> X
lambdas。我不知道目前维护的建议是替换OVERLOADS_OF
宏(有一段时间了)。
c++2a反映提议可能允许您访问函数名称的默认参数和重载集,然后花哨的元编程可以让您生成OVERLOADS_OF
而无需宏。