我想编写一个接受rvalues和lvalue引用的可变参数模板函数。它将大写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;
}
我怎样才能让它发挥作用? 也许转换函数不起作用,因为rvalues实际上是一个不同的类型?他们是char * s?
我的想法是什么:
我是否必须对类型特征做些什么?
有R值参考的东西?
有普遍崇敬的东西(不是真的确定那是什么)?
请更正任何滥用术语的行为!
答案 0 :(得分:1)
了解通用参考资料。这是一个更好的方式(恕我直言)思考这些事情,我觉得他的视频一般很好地解释了右值参考。
答案 1 :(得分:1)
首先,程序不起作用的根本原因不仅与rvalue / lvalue兼容性有关。为了表明考虑这个只通过值传递参数的版本
#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);
不起作用,因为编译器认为第一个参数是“一个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*’
现在回到原来的左值/右值问题(折叠规则说&amp;&amp;&amp; =&amp;。这是解决方案。你也不能忘记“完美地向前”rvalue引用。
然后,最终答案的摘要是
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
编辑:不确定如何处理the standard中描述的此问题。