为什么std :: endl会生成这个神秘的错误消息?

Chr*_*s_F 8 c++ iostream compiler-errors variadic-templates c++11

如果我尝试编译以下代码,我得到以下编译器错误(请参阅代码.)如果std::endl删除它编译没有错误.

#include <iostream>
#include <sstream>
#include <utility>

namespace detail
{
    template <class T>
    void print(std::ostream& stream, const T& item)
    {
        stream << item;
    }

    template <class Head, class... Tail>
    void print(std::ostream& stream, const Head& head, Tail&&... tail)
    {
        detail::print(stream, head);
        detail::print(stream, std::forward<Tail>(tail)...);
    }
}

template <class... Args>
void print(std::ostream& stream, Args&&... args)
//note: candidate function not viable: requires 3 arguments, but 4 were provided
{
    std::stringstream ss;
    detail::print(ss, std::forward<Args>(args)...);
    stream << ss.rdbuf();
}

int main()
{
    print(std::cout, "The answer is ", 42, std::endl);
    //error: no matching function for call to 'print'
}
Run Code Online (Sandbox Code Playgroud)

R S*_*ahu 10

std::endl是一个功能模板.使用它时,必须由编译器显式指定或推导其模板参数.

std::ostream 有一个过载:

basic_ostream<charT,traits>& operator<<(
    basic_ostream<charT,traits>& (*pf) (basic_ostream<charT,traits>&) );
Run Code Online (Sandbox Code Playgroud)

当我们使用

std::cout << std::endl;
Run Code Online (Sandbox Code Playgroud)

编译器推断出要用于的类型std::endl.由于您在调用时无法使用自动类型扣除print,因此您必须明确std::endl要使用哪个版本.

以下应该有效:

print(std::cout, "The answer is ", 42, std::endl<char, std::char_traits<char>>);
Run Code Online (Sandbox Code Playgroud)

更新

我使用以下精简代码来跟踪问题:

#include <iostream>

namespace detail
{
   template <class T>
      void print(std::ostream& stream, const T& item)
      {
         stream << item;
      }
}

int main()
{
    // detail::print(std::cout, std::endl);
    detail::print(std::cout, std::endl<char, std::char_traits<char>>);
}
Run Code Online (Sandbox Code Playgroud)

  • 小挑剔,它是模板类型演绎,不是ADL.(ADL指的是基于参数类型的名称查找;但是名称查找在此处成功) (2认同)
  • 要详细说明@Matt的观点,[这里](http://coliru.stacked-crooked.com/a/919c935a089efa20)"ADL`正在由ADL找到.在您的示例中不会发生这种情况,因为没有对`endl`的无限制引用 (2认同)

M.M*_*M.M 5

我认为这是因为如果传递函数模板,模板类型推导会失败.它无法推断出要实例化的参数endl.

注意,定义endl是:

template <class charT, class traits> 
basic_ostream<charT,traits>& endl (basic_ostream<charT,traits>& os);
Run Code Online (Sandbox Code Playgroud)

更简单的例子:

template<class U> void func(U &u) { }

template<class T>
void print(const T &item) { }

int main()
{
print(func);    // error: matching function for call to 'print(<unresolved overloaded function type>)'
}
Run Code Online (Sandbox Code Playgroud)

您的错误消息是因为它尝试了各种方法来匹配您的函数调用参数包,但没有一个工作.

  • 为了证明这一点:http://coliru.stacked-crooked.com/a/00794615023c09b4 (2认同)