C++ concat中的变量模板和推断返回类型 这很有效
玩弄C++11,我试图通过将任意对象写入ostringstream来构建一个连接任意对象的函数。作为这些工具的帮助函数,我有一个可变的帮助函数,它将单个项目附加到下面完整粘贴中给出的现有ostream More上下文中:C++ concat中的变量模板和推断返回类型 这很有效,c++,c++11,g++,type-inference,variadic-templates,C++,C++11,G++,Type Inference,Variadic Templates,玩弄C++11,我试图通过将任意对象写入ostringstream来构建一个连接任意对象的函数。作为这些工具的帮助函数,我有一个可变的帮助函数,它将单个项目附加到下面完整粘贴中给出的现有ostream More上下文中: template<class Head, class... Tail> std::ostream& append(std::ostream& out, const Head& head, const Tail&... tail) {
template<class Head, class... Tail>
std::ostream& append(std::ostream& out, const Head& head, const Tail&... tail)
{
return append(out << head, tail...);
}
问题
所以我的核心问题是:
这段代码失败的原因是否充分
我感兴趣的要么是引用标准中说我的代码无效的部分,要么是对实现中出现的问题的一些见解。如果有人为此发现了一个gcc错误,这也是一个答案。我还没有找到合适的报告。尽管使用std::ostream仅对我当前的应用程序有效,但实现这一点的方法也很好。关于其他编译器如何处理这一点的输入也很受欢迎,但对于我将接受的答案来说,这是不够的。
3.3.2[基本范围pdecl]
-1-名称的声明点紧跟在其完整声明人第8条之后,以及其初始值设定人(如有)之前,除非下文另有说明
函数声明符包含尾部返回类型,因此函数本身的名称不在其尾部返回类型的范围内
所以在表达式decltypeappendout中
3.3.2[基本范围pdecl]
-1-名称的声明点紧跟在其完整声明人第8条之后,以及其初始值设定人(如有)之前,除非下文另有说明
函数声明符包含尾部返回类型,因此函数本身的名称不在其尾部返回类型的范围内
因此,在表达式decltypeappendout中,我发现添加带有行号的代码和带有行号的错误很有趣,但这些行号不匹配。您确定错误在尾部返回类型中吗?您可以通过将append return设置为void来测试这一点,因为您根本不使用返回类型,所以不需要返回任何内容。注意,我看不出该代码在语法层面上有任何明显的错误,我相信它应该编译。你测试过其他编译器吗?@DavidRodríguez dribeas:是的,它是尾随返回类型。根据Jonathan Wakely的回答,这甚至是有道理的。使用void返回类型确实会使问题消失,正如您所指出的,这似乎是一个完美的解决方法。所以我想请你们也提出这一点作为回答,这样我也可以给你们投票。这些答案可以很好地相互补充,一个给出原因,另一个给出解决方法。我发现有趣的是,您添加了带有行号的代码,以及带有行号的错误,但这些行号不匹配。您确定错误在尾部返回类型中吗?您可以通过将append return设置为void来测试这一点,因为您根本不使用返回类型,所以不需要返回任何内容。注意,我看不出该代码在语法层面上有任何明显的错误,我相信它应该编译。你测试过其他编译器吗?@DavidRodríguez dribeas:是的,它是尾随返回类型。根据Jonathan Wakely的回答,这甚至是有道理的。使用void返回类型确实会使问题消失,正如您所指出的,这似乎是一个完美的解决方法。所以我想请你们也提出这一点作为回答,这样我也可以给你们投票。这些答案将很好地相互补充,一个给出原因,另一个给出解决方法。无论是在内容上还是在表达上,答案都很棒。谢谢在这种特殊情况下,另一个解决方法是使ADL能够在实例化时找到它。我想这种类型的s可能会被滥用。类似于struct MyADLFinder:std::ostringstream{};考虑到函数的使用,第三个更简单的解决方法是根本不返回任何内容,并且具有一个void返回类型。@DavidRodríguez dribeas,是的,这更有意义!无论是在内容上还是在表达上,答案都很好。谢谢在这种特殊情况下,另一个解决方法是使ADL能够在实例化时找到它。我想这种类型的s可能会被滥用。类似于struct MyADLFinder:std::ostringstream{};考虑到函数的使用,第三个更简单的解决方法是根本不返回任何内容,并且具有一个void返回类型。@DavidRodríguez dribeas,是的,这更有意义!
1 #include <iostream>
2 #include <sstream>
3
4 template<typename Stream>
5 Stream& append(Stream& out) {
6 return out;
7 }
8
9 template<class Stream, class Head, class... Tail>
10 auto append(Stream& out, const Head& head, const Tail&... tail)
11 -> decltype(append(out << head, tail...)) // <<<<< This is the important line!
12 {
13 return append(out << head, tail...);
14 }
15
16 template<class... Args>
17 std::string concat(const Args&... args) {
18 std::ostringstream s;
19 append(s, args...);
20 return s.str();
21 }
22
23 int main() {
24 std::cout << concat("foo ", 3, " bar ", 7) << std::endl;
25 }
In instantiation of ‘std::string concat(const Args& ...) [with Args = {char [5], int, char [6], int}; std::string = std::basic_string<char>]’:
24:44: required from here
19:3: error: no matching function for call to ‘append(std::ostringstream&, const char [5], const int&, const char [6], const int&)’
19:3: note: candidates are:
5:9: note: template<class Stream> Stream& append(Stream&)
5:9: note: template argument deduction/substitution failed:
19:3: note: candidate expects 1 argument, 5 provided
10:6: note: template<class Stream, class Head, class ... Tail> decltype (append((out << head), append::tail ...)) append(Stream&, const Head&, const Tail& ...)
10:6: note: template argument deduction/substitution failed:
In substitution of ‘template<class Stream, class Head, class ... Tail> decltype (append((out << head), tail ...)) append(Stream&, const Head&, const Tail& ...) [with Stream = std::basic_ostringstream<char>; Head = char [5]; Tail = {int, char [6], int}]’:
19:3: required from ‘std::string concat(const Args& ...) [with Args = {char [5], int, char [6], int}; std::string = std::basic_string<char>]’
24:44: required from here
10:6: error: no matching function for call to ‘append(std::basic_ostream<char>&, const int&, const char [6], const int&)’
10:6: note: candidate is:
5:9: note: template<class Stream> Stream& append(Stream&)
5:9: note: template argument deduction/substitution failed:
10:6: note: candidate expects 1 argument, 4 provided
template<class Stream, class Head, class... Tail>
auto append(Stream& out, const Head& head, const Tail&... tail)
-> typename std::common_type<decltype(out << head), decltype(out << tail)...>::type