I'm severely suffering from the 'morning after the night before' syndrome and have even trouble using a keyboard! I knew it was a mistake having it during the week. Never again. If I type nonsense please have some patience...
I have this code that seems to do as expected for the return type:
#include <string>
#include <string_view>
#include <iostream>
auto test(std::string_view) {
std::string_view output { "sv" };
std::cout << "Process sv\n";
return output;
}
auto test(constchar*) {
std::string output { "s" };
std::cout << "Process char*\n";
return output;
}
auto test(std::string&) {
std::string_view output { "sv" };
std::cout << "Process s&\n";
return output;
}
int main() {
std::string s { "foobar" };
std::string_view sv { "qwerty" };
std::cout << test("qwerty") << '\n'; // Should return type std::string
std::cout << test(s) << '\n'; // Should return type std::string_view
std::cout << test(sv) << '\n'; // Should return type std::string_view
}
The processing undertaken within each test function is the same (not shown for brevity and not relevant). What I'd like is these 3 to be combined in one function with the return type std::string if the func param is a temp (rvalue) otherwise type std::string_view. My brain currently refuses to process this...
Yes - for when the arg is an lvalue the return string_view is valid as it's referencing into the passed arg. If the passed is a temp/rvalue then that's why return a string.
#include <iostream>
#include <string>
#include <string_view>
// if a temporary is bound to the reference parameter str, that temporary object
// exists only until the end of the full expression containing the call to this this function
std::string_view foo( const std::string& str )
{
return str ;
}
int main()
{
const std::string str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ" ;
constauto a = foo(str) ; // this is fine
std::cout << a.substr(2) << '\n' ;
constauto b = foo( str.substr(2) ) ; // the temporary object (substring) is destroyed at the end of this full expression
std::cout << b << '\n' ; // *** UB *** (the string_view outlives the pointed-to character array)
}
Yes - so for L19 foo() should return a std::string and not std::string_view as the passed arg is a temp. For an lvalue arg (or an arg referring to an lvalue) return std::string_view otherwise return std::string.
Updated main() test code:
1 2 3 4 5 6 7 8 9
int main() {
std::string s { "foobar" };
std::string_view sv { "qwerty" };
std::cout << test("qwerty") << '\n'; // Returns std::string OK
std::cout << test(s) << '\n'; // Returns std::string_view OK
std::cout << test(sv) << '\n'; // Returns std::string_view OK
std::cout << test(s.substr(2)) << '\n'; // Should return type std::string - ERROR - RETURNS string_view
}
L8 is in error. The type returned should be std::string and NOT std::string_view
#include <string>
#include <string_view>
#include <iostream>
#include <typeinfo>
template<typename T>
requires std::same_as<T, std::string> || std::same_as<T, std::string_view>
T test1(std::string_view) {
T output { typeid(T).name() };
return output;
}
auto test(std::string_view s) {
return test1<std::string_view>(s);
}
auto test(constchar* s) {
return test1<std::string>(s);
}
auto test(std::string&& s) {
return test1<std::string>(s);
}
auto test(std::string& s) {
return test1<std::string_view>(s);
}
int main() {
std::string s { "foobar" };
std::string_view sv { "qwerty" };
std::cout << test("qwerty") << '\n'; // Returns std::string OK
std::cout << test(s) << '\n'; // Returns std::string_view OK
std::cout << test(sv) << '\n'; // Returns std::string_view OK
std::cout << test(s.substr(2)) << '\n'; // Returns std::string OK
}
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
class std::basic_string_view<char,struct std::char_traits<char> >
class std::basic_string_view<char,struct std::char_traits<char> >
class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >
For C++20/23 is there a 'better' way of doing this without all the overloading?