C++: Constructor accepting only a string literal

Viewed 6643

Is it possible to create a constructor (or function signature, for that matter) that only accepts a string literal, but not an e.g. char const *?

Is it possible to have two overloads that can distinguish between string literals and char const *?

C++ 0x would kind-of allow this with a custom suffix - but I'm looking for an "earlier" solution.

Rationale: avoiding heap copy of strings that won't be modified when given as string literals.

These strings directly go to an API expecting a const char * without any processing. Most calls do use literals requiring no additional processing, only in a few cases they are constructed. I am looking for a possibility to preserve the native call behavior.

Note: - since it comes up in the answers: the code in question does not use std::string at all, but a good example would be:

class foo
{
   std::string m_str;
   char const * m_cstr;      
 public:
   foo(<string literal> s) : m_cstr(p) {}
   foo(char const * s) : m_str(s) { m_cstr = s.c_str(); }
   foo(std::string const & s) : m_str(s) { m_cstr = s.c_str(); }

   operator char const *() const { return m_cstr; }
}

Results:

(1) it can't be done.
(2) I realized I am not even looking for a literal, but for a compile-time-constant (i.e. "anything that needs not be copied").

I will probably use the following pattern instead:

const literal str_Ophelia = "Ophelia";

void Foo()
{
  Hamlet(str_Ophelia, ...);  // can receive literal or string or const char *
}

with a simple

struct literal  
{ 
   char const * data; 
   literal(char const * p) : data(p) {} 
   operator const char *() const { return data; }
};

That doesn't stop anyone from abusing it (I should find a better name...), but it allows the required optimization but remains safe by default.

6 Answers

Working solution based on sbi idea:

struct char_wrapper
{
    char_wrapper(const char* val) : val(val) {};
    const char* val;
};

class MyClass {
public:
  template< std::size_t N >
  explicit MyClass(const char (&str)[N])
  {
      cout << "LITERAL" << endl;
  }
  template< std::size_t N >
  explicit MyClass(char (&str)[N])
  {
      cout << "pointer" << endl;
  }    
  MyClass(char_wrapper m)
  {
     cout << "pointer" << endl;
  }
};

int main()
{
    MyClass z("TEST1");     // LITERAL
    const char* b = "fff";
    MyClass a(b);           // pointer
    char tmp[256]; 
    strcpy(tmp, "hello"); 
    MyClass c(tmp);         // pointer
}

No, you just can't do this - string literals and const char* are interchangeable. One workaround could be to introduce a special class to hold pointers to string literals and make a constructor only accepting that. This way whenever you need to pass a literal you call a constructor of that class and pass the temporary object. This doesn't completely prevent misuse, but makes code much more maintainable.

If you know exactly how your compiler and platform deal with string literals, it might be possible to write a solution that can do this. If you know that your compiler always puts string literals into a specific region of memory, you can check the pointer against the bounds of that memory. If it falls within that block, you've got a string literal; otherwise you've got a string stored on the heap or stack.

However, this solution would be platform/compiler-specific. It would not be portable.

On some platforms, I have had to declare string literals as static const char * in order for the program to access the text from Read-Only Memory. When declared as const char *, the assembly listing showed that the text was copied from ROM onto a stack variable.

Instead of worrying about the receiver, perhaps try declaring the string literals with static const char *.

Related