MvG*_*MvG 1 c++ type-inference g++ variadic-templates c++11
玩弄C++ 11,我尝试构建一个函数,通过将任意对象写入一个来连接它们ostringstream.作为那些辅助函数,我有一个可变辅助函数,它将一个项目附加到现有函数ostream(下面的完整粘贴中给出的更多上下文):
template<class Head, class... Tail>
std::ostream& append(std::ostream& out, const Head& head, const Tail&... tail)
{
return append(out << head, tail...);
}
Run Code Online (Sandbox Code Playgroud)
但后来我认为可能有一些对象,当<<应用于流时,不会返回ostream而是返回一些占位符.因此,将流类型设置为模板参数也很酷:
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 }
Run Code Online (Sandbox Code Playgroud)
但是g++-4.7.1会拒绝编译这个.
将Stream签名中的所有用法改回来std::ostream都不会让它变得更好,所以我假设新的函数声明语法在这里发挥了重要作用 - 即使gcc 声称自4.4以来支持它.
错误信息相当神秘,并没有告诉我这里发生了什么.但也许你可以理解它.
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
Run Code Online (Sandbox Code Playgroud)
所以我的核心问题是:
这个代码是否有充分的理由失败?
我会对标准中引用我的代码无效的一些引用感兴趣,或者对实现中出现问题的一些见解感兴趣.如果有人应该为此找到一个gcc bug,那也是一个答案.我找不到合适的报告.使这项工作的方法也很棒,尽管使用std::ostream仅适用于我当前的应用程序.关于其他编译器如何处理这个问题的输入也很受欢迎,但对于我认为可以接受的答案来说还不够.
3.3.2 [basic.scope.pdecl]
-1-名称的声明点紧跟在其完整的声明者(第8条)之后和初始化者之前(如果有的话),除非如下所述.
函数声明符包含尾随返回类型,因此函数自己的名称不在其自己的尾随返回类型的范围内.
因此在表达式decltype(append(out << head, tail...))中唯一的候选函数是非变量函数append(Stream&),当参数包tail不为空时不能使用它,因此当append使用两个以上的参数调用时,演绎总是失败.
因此,GCC拒绝代码是正确的.
去年12月,标准委员会成员对此进行了讨论,并将其作为核心问题报告,参见CWG 1433.
我现在能想到的唯一解决方法是尝试使用common_type,这在某些情况下会起作用,但对其他情况可能会失败:
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
Run Code Online (Sandbox Code Playgroud)
如果out << head << tail有效但是out << tail没有,或者如果任何operator<<调用返回无法转换为其他operator<<调用返回的类型的内容,则会失败.
| 归档时间: |
|
| 查看次数: |
873 次 |
| 最近记录: |