Wal*_*ter 5 c++ templates argument-passing variadic-templates c++11
编辑这不是对静态类成员的未定义引用的重复.那个问题探讨了问题的原因(我在下面解释).在这里,我正在寻找与那些问题的答案中提出的解决方案不同的解决方案(这意味着更改constexpr要使用的变量的声明/定义- 主要是通过在编译单元中添加定义).
我已经创建了一个小的可变参数模板函数make_string()来生成std::string任意数量的io-able参数,如下所示.
using std::ostringstream; // just for this example
inline ostringstream&write(ostringstream&ostr, const char*x)
{ if(x) ostr<<x;  return ostr; }
template<class T>
inline ostringstream&write(ostringstream&ostr, T const&x)
{ ostr<<x;  return ostr; }
inline ostringstream&write(ostringstream&ostr) noexcept
{ return ostr; }
template<class T, class... R>
inline ostringstream&write(ostringstream&ostr, T const&x, R&&... r)
{ return write(write(ostr,x), std::forward<R>(r)...); }
inline std::string make_string(const char*text)
{ return {text?text:""}; }
inline std::string make_string(std::string const&text)
{ return {text}; }
template<typename T>
inline auto make_string(T var) -> decltype(std::to_string(var))
{ return std::to_string(var); }
template<class... Args>
inline std::string make_string(Args&&... args)
{
  ostringstream ostr;
  write(ostr,std::forward<Args>(args)...);
  return std::move(ostr.str());
}
现在,这很好用,可以像这样使用
throw std::runtime_error(make_string("offset=",offset," > max_offset =",
                                      max_offset"));
但是,在打印static constexpr类成员时存在问题,如
class foo
{
   static constexpr int max_offset=some_value;
   // ...
   void bar(int offset)
   {
     if(offset > max_offset)
     throw std::runtime_error(make_string("offset=",offset," > max_offset=",
                                          max_offset"));
   }
};
这会在链接时导致错误.原因是make_string它通过引用获取所有参数,包括static constexpr max_offset.因此,foo::max_offset链接时需要引用,另请参见.
如何在不放弃这个想法的情况下避免这个问题make_string()?(也许可以使用可变参数宏替换可变参数模板,但我会将其视为某种回归.)make_string必须有一种方法可以通过值或引用来获取其参数,具体取决于类型(以便内置类型可以取值).怎么样?
首先,我不确定为什么你需要这么多代码make_string。我简单地将其定义为
template<class... Args>
inline std::string make_string(Args&&... args)
{
  ostringstream ostr;
  _do{ostr << std::forward<Args>(args)...};
  return std::move(ostr.str());
}
在哪里
struct _do { template <typename... T> _do(T&&...) { } };
是一个辅助结构体,可让您以正确的顺序计算表达式(但请注意,至少在 4.9 之前,GCC会错误地从右到左计算)。
现在,回答你的问题。正如我在评论中所说,我觉得你的问题与 无关make_string。在对静态类成员的未定义引用中,在我的问题中通过通用引用传递静态 constexpr 变量?,在我见过的所有相关问题中,建议的答案是在类外的某处定义变量:
constexpr int foo::max_offset;
我不确定这对你来说是否是个问题。这对我来说是一个问题,因为在大量模板化的代码中,它意味着太多的重复(请参阅我的问题下面的讨论)。无论如何,如果这是一个问题,我会看到其他一些简单的解决方案来确保按值调用:
使用make_string(..., int(max_offset))而不是make_string(..., max_offset)
作为快捷方式,+max_offset执行相同的工作(此处建议)
定义static constexpr int max_offset() { return some_value; },然后使用max_offset()而不是贯穿max_offset始终
让代码的某些部分(函数或模板)推导max_offset为非类型int模板参数,然后直接使用它
最后,定义make_string(Args... args)(这是最简单的,但不适用于此处,因为您不想复制所有这些字符串)
我不是在讨论make_string抛出异常的用法;这是一个不同的问题。
| 归档时间: | 
 | 
| 查看次数: | 449 次 | 
| 最近记录: |