可变参数化模板函数(printf)的函数模板专业化

问题描述 投票:1回答:2

我有一些我要改进的Arduino C ++ 11代码:尝试使类似printf的函数对String进行特殊处理,因此我不必在使用它的任何地方自己调用c_str()。基本上,对于任何内置类型(如int float bool等),我只想按原样传递arg,对于String,则传递返回c_str()。遇到一些障碍,所以我在一些可用的在线编译器中尝试了此操作。起点是这样,使用std :: string而不是String:

#include <string>

class SerialOut {
public:
    template<class ...Ts>
    static void error(const char* msg, Ts... args) {
        printf(msg, args...);
    }
};

int main() {
    std::string greeting("hi");
    SerialOut::error("Message %d %s\n", 1, greeting.c_str());
}

所以我尝试创建一个函数模板,该模板仅返回其获取的值,并带有std :: string:的特殊化]

#include <string>

template <typename T, typename R=T> R raw(T& x) {return x;}
template <> const char* raw<>(std::string& x) {return x.c_str();}

class SerialOut {
public:
    template<class ...Ts>
    static void error(const char* msg, Ts... args) {
        printf(msg, raw(args)...);
    }
};

int main() {
    std::string greeting("hi");
    SerialOut::error("Message %d %s\n", 1, greeting);
}

我在https://repl.it/languages/cpp11中运行此命令时遇到编译错误:

clang version 7.0.0-3~ubuntu0.18.04.1 (tags/RELEASE_700/final)
 clang++-7 -pthread -std=c++11 -o main main.cpp
main.cpp:10:25: error: cannot pass object of non-trivial type
      'std::__cxx11::basic_string<char>' through variadic function; call will abort at
      runtime [-Wnon-pod-varargs]
            printf(msg, raw(args)...);
                        ^
main.cpp:16:20: note: in instantiation of function template specialization
      'SerialOut::error<int, std::__cxx11::basic_string<char> >' requested here
        SerialOut::error("Message %d %s\n", 1, greeting);
                   ^
1 error generated.
compiler exit status 1

https://www.onlinegdb.com/online_c++_compiler没有错误,但是未选择raw()特殊化,因此问候的输出为垃圾。

[在Arduino IDE中,我得到了一个稍微不同的错误(当然,用String替换了std :: string之后:]]]

sketch\mqtt.cpp.o: In function `char const* raw<String, char const*>(String&)':

sketch/utils.h:15: multiple definition of `char const* raw<String, char const*>(String&)'

sketch\Thermistor.cpp.o:sketch/utils.h:15: first defined here

sketch\sketch.ino.cpp.o: In function `char const* raw<String, char const*>(String&)':

sketch/utils.h:15: multiple definition of `char const* raw<String, char const*>(String&)'

sketch\Thermistor.cpp.o:sketch/utils.h:15: first defined here

我尝试了raw()函数的几种变体,但无济于事。我认为我只是缺少一个微妙之处,或者在C ++ 11中无法做到这一点。

[Update

:我发现Variadic Macro: cannot pass objects of non-trivially-copyable type through '...',答案之一解决了C ++ 14中的上述问题(基本上使用decltype(auto)和重载而不是专业化)。我对其添加了一个细微的变化,它也可以在C ++ 11中使用,并且使用“内联”它也可以在Arduino C ++中使用(对于重载,上面没有关于多个定义的消息,而没有“内联”)—原来这是一个链接器消息,以便它可以编译,我想Arduino变体不像其他编译器那样内联“明显内联”功能)。

我有一些我要改进的Arduino C ++ 11代码:尝试使类似printf的函数对String进行特殊处理,因此我不必在使用它的任何地方自己调用c_str()。基本上对于任何...

string c++11 variadic-templates arduino-c++
2个回答
0
投票

沿着这些思路的东西,也许:

template <typename T>
struct SerialHelper {
    static T raw(T val) { return val; }
};

template <>
struct SerialHelper<std::string> {
    static const char* raw(const std::string& val) { return val.c_str(); }
};


class SerialOut {
public:
    template<class ...Ts>
    static void error(const char* msg, Ts... args) {
        printf(msg, SerialHelper<Ts>::raw(args)...);
    }
};

0
投票

以下内容在C ++ 11和Arduino C ++中有效:

© www.soinside.com 2019 - 2024. All rights reserved.