使用模板让printf()与std :: string

时间:2018-02-27 00:47:44

标签: c++ templates clang variadic-templates

我想生成printf版本,该版本会自动将其std::string参数转换为c_str()个值。 (我发现printf语法比C ++流更清晰,更简单。

我想用简单的东西。简短而简单是唯一的设计目标。 Boost有这样的东西,但它太复杂了。我根本不关心效率或完全避免复制。

下面是一个几乎与一个参数一起使用的简单示例。代码有两个问题:

(1)如何将其扩展为任意数量(或至少3个)参数?我知道我可以使用可变参数模板,但我不明白如何在这里使用它们。

(2)当格式参数clang与要打印的实际对象之间存在类型不匹配时,如何保持编译器警告(-Wallconst char*)?

编辑:第(2)部分已基本解决。我在__attribute__((format printf,1,2))之前添加myprint()。这样做了类型检查,但要求myprint是可变的。

示例代码:

#include <stdio.h>
#include <string>
using std::string;
template <typename T>
void myprint(const char* format, T arg){
  printf(format, arg);
}

template <>
void myprint(const char* format, string arg){
  printf(format,(arg+" STRING ").c_str());
}

int main(){
  string x("foo");
  myprint ("The value of 1 is: %s\n", "simple"); //works
  myprint ("The value of 2 is: %s\n", x); // works
  myprint ("The value of 2 is: %d\n", x); // fails - no warning!
  printf ("The value of 2 is: %d\n", x.c_str()); // works - warning
  return 0;
}

1 个答案:

答案 0 :(得分:0)

这里有一个想法:

namespace io {
template <class X>
using is_string = typename std::enable_if<std::is_same<X, std::string>::value>::type;

template <class X>
using is_not_string = typename std::enable_if<!std::is_same<X, std::string>::value>::type;

template <class T, class = is_not_string<T>>
constexpr T forward_or_transform(T t) {
    return std::forward<T>(t); 
}

template <class T, class = is_string<T>>
constexpr const char* forward_or_transform(T t) { 
    return t.c_str(); 
}

template <class ...Ti>
int printf(const std::string& format, Ti...t) {
    return std::printf(format.c_str(), forward_or_transform(t)...);
}
}

auto s = std::string("const std::string&");
io::printf("[%s]-[%s]-[%s]-[%d]\n", std::string("std::string&&"), "const char *", s, 42);

打印:[std::string&&]-[const char *]-[const std::string&]-[42]