'const std::string&' 之后的变量参数列表弄乱了堆栈

Variable Argument List following 'const std::string&' messes up the stack

我有一个函数:std::string format(const std::string sformat, ...); 它基本上像花哨的 sprintf() 一样工作。

因为我经常调用该函数,所以我想将格式字符串作为引用传递:const std::string& sformat。 不幸的是 va_start() 似乎无法在堆栈中找到变量参数列表的正确位置。

如果我删除“&”,它就可以正常工作。

两个问题:A: 我什至需要参考以防止在调用期间复制 sformat ,还是优化器足够聪明,只在后台传递参考? B: 我该怎么做才能防止格式字符串的按值传递并且仍然不会混淆 va_start() ?

我的猜测是:指针传递。或者有更好的解决方案吗?

namespace details {
  std::string format(char const* sformat, ...) {
    // code
  }
}
template<class...Args>
std::string format(std::string const& str, Args const&... args) {
  return details::format( str.data(), args... );
}

作为奖励,我可以写一个 to_pod 助手:

namespace details {
  std::string format(char const* sformat, ...) {
    // code
  }
}
template<class T>
T const& to_pod(T const& t){ return t; }
template<class Char, class Attribs>
Char const* to_pod( std::basic_string<Char, Attribs> const& str ) {
  return t.data();
}
template<class...Args>
std::string format(std::string const& str, Args const&... args) {
  return details::format( str.data(), to_pod(args)... );
}

现在我可以将 std::strings 作为传递给第一个参数的东西,它们会自动转换为 char const* 指向其缓冲区的指针。

...

如果您没有 C++11 编译器(比如 MSVC 2010),您最好的选择可能就是编写重载。

std::string format(std::string const& str) {
  return details::format( str.data() );
}
template<class A0>
std::string format(std::string const& str, A0 const& a0) {
  return details::format( str.data(), to_pod(a0) );
}
template<class A0, class A1>
std::string format(std::string const& str, A0 const& a0, A1 const& a1) {
  return details::format( str.data(), to_pod(a0), to_pod(a1) );
}
// etc

您可能不需要超过 10 个参数。