简体   繁体   English

参数包参数类型

[英]parameter packs parameter type

I have modified the sample from https://en.cppreference.com/w/cpp/language/parameter_pack to save the string in a variable.我已经修改了https://en.cppreference.com/w/cpp/language/parameter_pack中的示例,以将字符串保存在变量中。 My code我的代码

#include <string>

void tprintf(std::string& str, const std::string& format) 
{
    str += format; 
}

template <typename T, typename... Targs>
void tprintf(std::string& str, const std::string& format, T arg, Targs ...Fargs)
{
    for ( int i = 0; i < format.size(); i++ )
    {
        if ( format.at(i) == '%' )
        {
            if (format.at(i + 1) == 'd') 
            {
                std::cout << "== 'd' -variable = " << arg << std::endl;
                str += std::to_string(arg);
            }
            else if (format.at(i + 1) == 's') 
            {
                std::cout << "== 's'" << std::endl;
                str += arg;
            }
            tprintf(str, (i + 2 < format.size() ? format.substr(i + 2) : ""), Fargs...);
            break;  
        }
        str += format.at(i);
    }
}

int main()
{
    std::string str;
    int age = 24;
    std::string name("Hugo");
    tprintf(str, "Name: %s, age: %d years\n", name, age);
    std::cout << "result = " << str << std::endl;
}

When compile the code I get the following error:编译代码时出现以下错误:

error: no matching function for call to ‘to_string(std::__cxx11::basic_string<char>&)’
                 str += std::to_string(arg);

I thought the parameter pack expands to我认为参数包扩展到

  1. tprintf(std::string&, const std::string&, std::string, int) <- arg is std::string tprintf(std::string&, const std::string&, std::string, int) <- argstd::string
  2. tprintf(std::string&, const std::string&, int) <- arg is int and I can call std::to_string(arg) But it seems that arg has another type than int ( std::string or something else)? tprintf(std::string&, const std::string&, int) <- argint ,我可以调用std::to_string(arg)但似乎arg具有除int之外的另一种类型( std::string或其他类型) ? When I remove the std::to_string call I get some cryptic characters.当我删除std::to_string调用时,我得到了一些神秘字符。

How can I convert the value for the age to a string and append it to str ?如何将年龄的值转换为string并将 append 转换为str

tprintf(std::string&, const std::string&, std::string, int) <- arg is std::string tprintf(std::string&, const std::string&, std::string, int) <- arg 是 std::string

Correct, therefore, here:因此,这里是正确的:

 str += std::to_string(arg);

arg is a std::string , and there is no such std::to_string overload. arg是一个std::string ,并且没有这样的std::to_string重载。

No matter what type T is, the resulting template must be valid C++ code.无论T是什么类型,生成的模板必须是有效的 C++ 代码。 Even if the corresponding formatting character is d , everything in the function must still be valid C++ code.即使对应的格式化字符是d , function 中的所有内容仍然必须是有效的 C++ 代码。

In general, attempting to implement C-style printf formatting, in type-safe C++ doesn't make much sense.一般来说,尝试在类型安全的 C++ 中实现 C 风格的printf格式没有多大意义。 You already know what needs to be formatted simply by the virtue of the fact that you know the type of the corresponding parameter.由于您知道相应参数的类型,因此您已经知道需要格式化什么。

The only reason you have different formatting specifiers in C-style printf strings, such as %s or %d , is because this C function has no clue, whatsoever, what is getting to passed to it, as a parameter, so it relies on the actual formatting specifier to know what it is.您在 C 风格printf字符串(例如%s%d )中有不同格式说明符的唯一原因是因为这个 C function 没有任何线索,所以它没有任何线索实际的格式说明符以了解它是什么。

This obviously isn't the case with C++. C++ 显然不是这种情况。 Your formatting specifier can be just a % , by itself, with nothing else.您的格式说明符本身可以只是一个% ,没有别的。 You know exactly what parameter gets passed in. Therefore, it's much simpler to merely define three overloaded functions:您确切地知道传入了什么参数。因此,仅定义三个重载函数要简单得多:

template <typename... Targs>
void tprintf(std::string& str, const std::string& format, int arg, Targs ...args)
{
   // Just the code that formats an int
}

template <typename... Targs>
void tprintf(std::string& str, const std::string& format, const std::string &arg, Targs ...args)
{
   // Just the code that formats a std::string
}

void tprintf(std::string& str, const std::string& format)
{
   // Nothing more to format, just adds everything else in "format" to "str".
}

In the first two cases, all that needs to happen is to search format for the first % place-holder by itself, copy everything before prior to it into str , followed by the formatted parameter, and then recursively re-invoke tprintf with the remaining args , and what's left in the format .在前两种情况下,只需要自行搜索第一个%占位符的format ,将其之前的所有内容复制到str中,然后是格式化参数,然后递归地重新调用tprintf其余的args ,以及format中剩下的内容。

PS Using forwarding references, "Targs &&...args", together with std::forward , will be a follow-up tweak. PS 使用转发引用,“Targs &&...args”,连同std::forward ,将是一个后续调整。

All branches of an if statement are compiled. if 语句的所有分支都被编译。 The compiler is attempting to pass the string argument to to string, and no overload exists.编译器正在尝试将字符串参数传递给字符串,并且不存在重载。

The fact that it doesn't happen at runtime is irrelevant.它不会在运行时发生的事实是无关紧要的。 At compile time, the compiler needs to know what在编译时,编译器需要知道什么

tprintf(str, "Name: %s, age: %d years\n", name, age);

does and what做什么做什么

tprintf(str, "Name: %d, age: %d years\n", name, age);

would do.会做。

Consider not including type information twice.考虑不包括类型信息两次。 You already know that name is a string and age is an integer, repeating it in the format string is pointless.您已经知道 name 是一个字符串,而 age 是一个 integer,在格式字符串中重复它是没有意义的。

I'd advise positional commands in a format string, as that makes localization far more practical as well.我建议使用格式字符串的位置命令,因为这也使本地化更加实用。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM