20

文字列リテラルのみを受け入れ、 eg を受け入れないコンストラクター (または関数シグネチャー) を作成することは可能char const *ですか?

文字列リテラルと を区別できる 2 つのオーバーロードを持つことは可能char const *ですか?

C++ 0x は、カスタム サフィックスを使用してこれを許可しますが、「以前の」ソリューションを探しています。

理由:文字列リテラルとして指定された場合に変更されない文字列のヒープ コピーを回避します。

const char *これらの文字列は、処理なしで API に直接送信されます。ほとんどの呼び出しは、追加の処理を必要としないリテラルを使用しますが、構築されるのはごくわずかです。ネイティブの通話動作を維持する可能性を探しています。

注: -回答に出てくるので、問題のコードはまったく使用std::stringしませんが、良い例は次のとおりです。

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; }
}

結果:

(1)それはできません。
(2)リテラルを探しているのではなく、コンパイル時定数(つまり、「コピーする必要のないもの」)を探していることに気付きました。

代わりに、おそらく次のパターンを使用します。

const literal str_Ophelia = "Ophelia";

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

シンプルで

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

誰かがそれを悪用するのを止めるわけではありませんが (もっと良い名前を見つける必要があります...)、必要な最適化を可能にしますが、デフォルトで安全なままです。

4

6 に答える 6

20

sbi アイデアに基づく実用的なソリューション:

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
}
于 2010-01-11T12:19:28.870 に答える
9

いいえ、これはできません。文字列リテラルと const char* は交換可能です。回避策の 1 つは、文字列リテラルへのポインターを保持する特別なクラスを導入し、それのみを受け入れるコンストラクターを作成することです。このようにして、リテラルを渡す必要があるときはいつでも、そのクラスのコンストラクターを呼び出して一時オブジェクトを渡します。これにより、誤用が完全に防止されるわけではありませんが、コードがより保守しやすくなります。

于 2010-01-11T11:06:57.093 に答える
3

コンパイラとプラットフォームが文字列リテラルをどのように処理するかを正確に知っている場合は、これを実行できるソリューションを作成できる可能性があります。コンパイラが常に文字列リテラルをメモリの特定の領域に配置することがわかっている場合は、そのメモリの境界に対してポインターをチェックできます。そのブロック内にある場合は、文字列リテラルを取得しています。そうしないと、ヒープまたはスタックに文字列が格納されます。

ただし、この解決策はプラットフォーム/コンパイラ固有のものになります。ポータブルではありません。

于 2010-01-11T11:43:56.633 に答える
1

C++14 の新しいユーザー定義リテラル (Clang 3.5 の場合 - C++11 でも動作します) を使用すると、洗練された解決策があります。

class Literal {
 public:
  explicit Literal(const char* literal) : literal_(literal) {}
  // The constructor is public to allow explicit conversion of external string
  // literals to `_L` literals. If there is no such need, then move constructor
  // to private section.

  operator const char* () { return literal_; }

 private:
  friend Literal operator"" _L (const char*, unsigned long);
  // Helps, when constructor is moved to private section.

  const char* literal_;
};

Literal operator"" _L (const char* str, unsigned long) {
  return Literal(str);
}

次のように使用できます。

void f1(Literal) {}  // Accepts literals only.

int main() {
  auto str1 = "OMG! Teh Rey!"_L;
  std::cout << str1 << std::endl;
  f(str1);
}

欠点が 1 つあります。すべてのリテラルに追加_Lする必要がありますが、実際には大したことではありません。

于 2014-06-13T08:49:04.007 に答える
1

static const char *一部のプラットフォームでは、プログラムが読み取り専用メモリからテキストにアクセスできるように、文字列リテラルを宣言する必要がありました。として宣言されたconst char *場合、アセンブリ リストは、テキストが ROM からスタック変数にコピーされたことを示していました。

レシーバーについて心配する代わりに、文字列リテラルを で宣言してみてくださいstatic const char *

于 2010-01-11T17:54:24.717 に答える