【问题标题】:perfect foward a parameter pack: convert args without expansion?完美转发参数包:在不扩展的情况下转换 args?
【发布时间】:2019-05-31 02:19:28
【问题描述】:

在单元测试中,我试图实现更实用的代码并简化一类函数调用,例如:

std::wstring widestr = std::wstring(o.Descr.begin(), o.Descr.end()); //o.Descr is string
wchar_t message[100];
swprintf(message, 100, L"size: %d", size);
Logger::WriteMessage(message);

进入:

Logger::WriteMessage(Message(L"string: %d", widestr.c_str()));

使用:

template<typename... T>
wchar_t* Message(T &&... args)
{
    wchar_t message[100];
    swprintf(message, 100, forward<T>(args)...);
    return message;
}

但输出不同:

而不是

1。我一开始就做正确的事吗?我错过了什么?

2。理想情况下,我想写类似 (c#) 的东西:

$"size:{size}".ToLogMessage();

我认为我不能在 c++{11,14,17} 中。你确认了吗?

Logger::WriteMessageMicrosoft.VisualStudio.TestTools.CppUnitTestFramework 的一部分,我无法更改它。

【问题讨论】:

  • 你在 windows aka visual c++ 上吗?如果是哪个版本?
  • 您的尝试无论如何都会返回一个悬空指针。
  • 对。我更正了这个问题。
  • 你不愿意使用std::w?string吗?
  • @UmNyobe VC++2017 版本 15.9 v14.16

标签: c++ c++11 functional-programming perfect-forwarding


【解决方案1】:

主要问题是你没有展开包:

template <typename... T>
wchar_t* Message(T &&... args)
{
    wchar_t message[100];
    swprintf(message, 100, forward<T>(args)...);
    return message;
}

但是,您还返回了一个悬空指针,这是一个大问题。

最终,如果Logger::WriteMessage 必须 接受一个指针,您将不得不将所有三行都包含在实用程序中。可能是这样:

template <typename... T>
void WriteLogMessage(T &&... args)
{
    wchar_t message[100];
    swprintf(message, 100, forward<T>(args)...);
    Logger::WriteMessage(message);
}

那么就:

WriteLogMessage(L"size: %d", size));

现在我请你考虑一下 Logger::WriteMessage 是否应该首先自己做这一切。

一旦你做到了,你可以考虑从swprintf切换到更像C++的东西,这样你就不需要依赖于任意的最大缓冲区大小。但是,使用字符串流和字符串并不是世界上最有效的事情,因此您还可以考虑执行两次swprintf:一次使用nullptr 输出只是为了获得结果字符串大小,然后再次实际放置将其放入大小正确的wchar_t 数组中……

...除了不幸的是,这只能通过snprintf 实现;对于宽字符串,您必须反复尝试使用越来越大的缓冲区,直到返回值表明您提供的缓冲区最终足够大。呃。

【讨论】:

  • 确实,但我使用的是using namespace Microsoft::VisualStudio::CppUnitTestFramework;,它不起作用。
  • @Soleil 那么WriteLogMessage 可能是你最好的选择。
  • 使用std::size(message) 可能比重复魔术100 更好。我也不相信转发到可变参数函数的优点(与可变参数模板相反)。
  • @Deduplicator std::size 是个好主意。可变参数模板很好但是..然后呢?你又回到了字符串流和大量的副本/分配,除非你可以引入 Boost.Format 或类似的东西。
猜你喜欢
  • 1970-01-01
  • 2021-05-25
  • 2022-01-04
  • 1970-01-01
  • 2019-01-16
  • 2015-08-26
  • 2013-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多