0

我想编写一个接受右值和左值引用的可变参数模板函数。它将大写 std::strings,并在大写后显示每个参数。函数结束后,所有左值都应保持大写(即通过引用传递左值)。
例如,我想要这种行为:

std::string hello = "hello";
std::string planet = "planet";
std::string earth = "earth";

//the order and amount of rvalues and lvalue references, should not matter
Capitalize_And_Output("hello","planet","earth"); //outputs: "HELLO PLANET EARTH"
Capitalize_And_Output(hello,"planet","earth");   //outputs: "HELLO PLANET EARTH"
Capitalize_And_Output("hello",planet,"earth");   //outputs: "HELLO PLANET EARTH"
Capitalize_And_Output("hello","planet",earth);   //outputs: "HELLO PLANET EARTH"
Capitalize_And_Output(hello,planet,"earth");     //outputs: "HELLO PLANET EARTH"
Capitalize_And_Output(hello,"planet",earth);     //outputs: "HELLO PLANET EARTH"
Capitalize_And_Output("hello",planet,earth);     //outputs: "HELLO PLANET EARTH"
Capitalize_And_Output(hello,planet,earth);       //outputs: "HELLO PLANET EARTH"

//lvalue references remain changed after the function call
std::cout << hello << std::endl;  //outputs: "HELLO"
std::cout << planet << std::endl; //outputs: "PLANET"
std::cout << earth << std::endl;  //outputs: "WORLD"

我怎样才能得到上面的代码块来编译和工作,如图所示?

到目前为止,我能够输出信息,但我不知道如何处理两种不同值类型的大写。以下代码编译,因为我已经注释掉了不起作用的行。

#include <string>
#include <iostream>
#include <algorithm>

template<typename T>
void Capitalize_And_Output(T & str) {
    //std::transform(str.begin(), str.end(), str.begin(), ::toupper); <- will not compile
    std::cout << str<< std::endl;
    return;
}

template<typename First, typename ... Strings>
void Capitalize_And_Output(First & str, const Strings&... rest) {
    //std::transform(str.begin(), str.end(), str.begin(), ::toupper); <- will not compile
    std::cout << str << " ";
    Capitalize_And_Output(rest...);
    return;
}

int main() {

    std::string hello = "hello";
    std::string planet = "planet";
    std::string earth = "earth";

    //the order and amount of rvalues and lvalue references, should not matter
    Capitalize_And_Output("hello","planet","earth"); //outputs: "HELLO PLANET EARTH"
    Capitalize_And_Output(hello,"planet","earth");   //outputs: "HELLO PLANET EARTH"
    Capitalize_And_Output("hello",planet,"earth");   //outputs: "HELLO PLANET EARTH"
    Capitalize_And_Output("hello","planet",earth);   //outputs: "HELLO PLANET EARTH"
    Capitalize_And_Output(hello,planet,"earth");     //outputs: "HELLO PLANET EARTH"
    Capitalize_And_Output(hello,"planet",earth);     //outputs: "HELLO PLANET EARTH"
    Capitalize_And_Output("hello",planet,earth);     //outputs: "HELLO PLANET EARTH"
    Capitalize_And_Output(hello,planet,earth);       //outputs: "HELLO PLANET EARTH"

    //lvalue references keep changed value after the function call
    std::cout << hello << std::endl;  //outputs: "HELLO"
    std::cout << planet << std::endl; //outputs: "PLANET"
    std::cout << earth << std::endl;  //outputs: "WORLD"

    return 0;
}

我怎样才能让它工作?
也许转换函数不起作用,因为右值实际上是不同的类型?它们是 char*s?

我脑子里在想什么:
我必须对类型特征做些什么吗?
有 R 值参考的东西?
具有普遍敬意的东西(虽然不太确定那是什么)?

请更正术语的任何滥用!

4

2 回答 2

1

http://channel9.msdn.com/Shows/Going+Deep/Cpp-and-Beyond-2012-Scott-Meyers-Universal-References-in-Cpp11

阅读有关通用参考的信息。这是思考这些事情的更好方式(恕我直言),我觉得他的视频很好地解释了右值引用。

于 2013-10-28T00:39:04.830 回答
1

首先,您的程序无法运行的根本原因不仅与右值/左值兼容性有关。为了表明考虑这个版本,它只通过值传递参数

#include <string>
#include <iostream>
#include <algorithm>

template<typename T>
void Capitalize_And_Output(T str) {
    std::transform(str.begin(), str.end(), str.begin(), ::toupper); 
    std::cout << str<< std::endl;
    return;
}

template<typename First, typename ... Strings>
void Capitalize_And_Output(First str, Strings... rest) {
    std::transform(str.begin(), str.end(), str.begin(), ::toupper); 
    std::cout << str << " ";
    Capitalize_And_Output(rest...);
    return;
}

在这种情况下,您的主代码也将不起作用。为了表明,考虑以下

int main() {    
    std::string hello = "hello";
    std::string planet = "planet";
    std::string earth = "earth";
    Capitalize_And_Output(std::string("hello"),planet,earth);  // this will work
    //Capitalize_And_Output("hello",planet,earth);  // original code -> this will NOT work
    return 0;
}

线

Capitalize_And_Output("hello",planet,earth);

不起作用,因为编译器考虑第一个参数“a const char”(char 没有 .begin() 和 .end() 迭代器!)!。实际上,我收到以下错误消息g++

instantiated from here
teste.cpp:14:5: error: request for member ‘begin’ in ‘str’, which is of non-class type ‘const char*’

现在回到你原来的左值/右值问题(折叠规则说 && & = &。这是解决方案。你也不能忘记“完美转发”右值引用。

然后,总结一下最后的答案

template<typename T>
void Capitalize_And_Output(T&& str) {
    std::transform(str.begin(), str.end(), str.begin(), ::toupper); // <- will not compile
    std::cout << str<< std::endl;
    return;
}

template<typename First, typename ... Strings>
void Capitalize_And_Output(First&& str, Strings&&... rest) {
    std::transform(str.begin(), str.end(), str.begin(), ::toupper); //<- will not compile
    std::cout << str << " ";
    Capitalize_And_Output(std::forward<Strings>(rest)...); // don't forget perfect forwarding.
    return;
}

加上在 main 中必须显式使用 std::string 构造函数的事实

    Capitalize_And_Output(std::string("hello"),planet,earth);  // this will work

编辑:不确定如何处理标准中描述的这个问题。

于 2013-10-28T01:44:05.287 回答