【问题标题】:How to use logger with template when using const char *?使用 const char * 时如何将记录器与模板一起使用?
【发布时间】:2019-06-06 11:06:47
【问题描述】:

以下链接中的代码无法按预期工作。我不知道我做错了什么。 https://coliru.stacked-crooked.com/a/f6ac59c7c20be10c

代码如下,错误信息在上面的链接中。

#include <iostream>
#include <string>

namespace Logger
{
    struct IStringable
    {
        virtual ~IStringable() {}
        virtual std::string ToString() const = 0;
    };

    std::string to_string(IStringable const& v) { return v.ToString(); }
    std::string to_string(const char* const& v) { return std::string(v); }

    template<class T>
    void log(T const& v)
    {
        using std::to_string;
        std::cout << "debug: " << to_string(v) << '\n';
    }
}

class Person : public Logger::IStringable {
public:
    Person(const std::string name) : _name(name) { }
    virtual std::string ToString() const { return _name; }
private:
    std::string _name;
};

int main()
{
    Person p("Alice");
    double d = 0.0;
    const char* c = "Some words";

    Logger::log(p); // Works
    Logger::log(d); // Works
    Logger::log(c); // Error

}

 

g++ -std=c++17 -O2 -Wall -Wextra -Werror -pedantic main.cpp && ./a.out
main.cpp: In instantiation of 'void Logger::log(const T&) [with T = const char*]':
main.cpp:39:18:   required from here
main.cpp:19:44: error: no matching function for call to 'to_string(const char* const&)'
         std::cout << "debug: " << to_string(v) << '\n';
                                   ~~~~~~~~~^~~

【问题讨论】:

  • 错误是什么?它以何种方式无法按预期工作?

标签: c++ templates inheritance name-lookup


【解决方案1】:

通过在函数体内使用using std::to_string;name lookup 将找不到命名空间Logger 中的名称to_string;当在函数范围内找到名称并且不再检查范围时,它将停止。

注意IStringable to_string(IStringable const&amp; v) 可以被ADL 找到,这对于像const char* 这样的内置类型不起作用。

1) 对于基本类型的参数,相关的命名空间和类集是空的

您可以将using std::to_string; 移出函数体。例如

using std::to_string;
template<class T>
void log(T const& v)
{
    std::cout << "debug: " << to_string(v) << '\n';
}

LIVE

【讨论】:

  • 好的,我明白了。但是为什么删除Logger:log(c)时代码有效,而删除Logger::log(p)却无效?
  • @GuySimonsen 我为它添加了一些解释。
【解决方案2】:

您可以为 Logger 命名空间添加另一个 using 声明来解决此问题:

template<class T>
void log(T const& v)
{
    using std::to_string;
    using Logger::to_string;

    // now use to_string...
}

第一个 using std::to_string 没有第二个就太具有侵略性了 - 它会导致名称查找过早终止。

【讨论】:

  • 你知道,这就是我首先发布答案的原因:)
  • 但我不明白错误是什么。如果我要删除 Logger:log(c) 代码将编译得很好,即使 Logger::log(p) 仍在使用
猜你喜欢
  • 2014-06-27
  • 2021-06-16
  • 1970-01-01
  • 1970-01-01
  • 2011-12-15
  • 1970-01-01
  • 2021-02-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多