How to cleanly use: const char* and std::string?

自古美人都是妖i 提交于 2019-12-04 10:35:33

One of the simplest solution is to use an C++ empty string. Here I declare empty string variable named _ and used it in front of string concatenation. Make sure you always put it in the front.

#include <cstdio>
#include <string>

using namespace std;
string _ = "";

int main() {
        char s[] = "chararray";
        string result =
                _ + "function name = [" + __FUNCTION__ + "] "
                "and s is [" + s + "]\n";
        printf( "%s", result.c_str() );
        return 0;
}

Output:

function name = [main] and s is [chararray]

Regarding __FUNCTION__, I found that in Visual C++ it is a macro while in GCC it is a variable, so SetReport("Failure in " __FUNCTION__ "; foobar was " + foobar + "\n"); will only work on Visual C++. See: https://msdn.microsoft.com/en-us/library/b0084kay.aspx and https://gcc.gnu.org/onlinedocs/gcc/Function-Names.html

The solution using empty string variable above should work on both Visual C++ and GCC.

The standard way to build a string, formatting non-string types as strings, is a string stream

#include <sstream>

std::ostringstream ss;
ss << "Failure in " << __FUNCTION__ << ": foobar was " << foobar << "\n";
SetReport(ss.str());

If you do this often, you could write a variadic template to do that:

template <typename... Ts> std::string str(Ts&&...);
SetReport(str("Failure in ", __FUNCTION__, ": foobar was ", foobar, '\n'));

The implementation is left as an exercise for the reader.

In this particular case, string literals (including __FUNCTION__) can be concatenated by simply writing one after the other; and, assuming foobar is a std::string, that can be concatenated with string literals using +:

SetReport("Failure in " __FUNCTION__ ": foobar was " + foobar + "\n");

If foobar is a numeric type, you could use std::to_string(foobar) to convert it.

Plain string literals (e.g. "abc" and __FUNCTION__) and char const* do not support concatenation. These are just plain C-style char const[] and char const*.

Solutions are to use some string formatting facilities or libraries, such as:

  • std::string and concatenation using +. May involve too many unnecessary allocations, unless operator+ employs expression templates.
  • std::snprintf. This one does not allocate buffers for you and not type safe, so people end up creating wrappers for it.
  • std::stringstream. Ubiquitous and standard but its syntax is at best awkward.
  • boost::format. Type safe but reportedly slow.
  • cppformat. Reportedly modern and fast.

My Solution

I've continued to experiment with different things and I've got a solution which combines tivn's answer that involves making an empty string to help concatenate long std::string and character arrays together and a function of my own which allows single line copying of that std::string to a const char* which is safe to use when the string object leaves scope.

I would have used Mike Seymour's variadic templates but they don't seem to be supported by the Visual Studio 2012 I'm running and I need this solution to be very general so I can't rely on them.

Here is my solution:

Strings.h

#ifndef _STRINGS_H_
#define _STRINGS_H_

#include <string>

// tivn's empty string in the header file
extern const std::string _;

// My own version of .c_str() which produces a copy of the contents of the string input
const char* ToCString(std::string input);

#endif

Strings.cpp

#include "Strings.h"

const std::string str = "";

const char* ToCString(std::string input)
{
    char* result = new char[input.length()+1];
    strcpy_s(result, input.length()+1, input.c_str());
    return result;
}

Usage

m_someMemberConstChar = ToCString(_ + "Hello, world! " + someDynamicValue);

I think this is pretty neat and works in most cases. Thank you everyone for helping me with this.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!