-4

文字列を入力として受け取る関数があるとします。

SomeOutputType f_impl(const char* s);

ほとんどの呼び出しサイトは、入力として文字列リテラルを使用するだけf("Hello, world")です。コンパイル時に結果を計算するために次の関数を実装したとします。

template <char...> SomeOutputType f_impl();

私の質問は、呼び出しサイトのようなf("Hello, world")呼び出しがテンプレート化されたフォームをstring s="Hello, world"; f(s.c_str());呼び出し、一般的な呼び出しサイトが一般的なフォームを呼び出すようにする方法はありますか? 明確にauto s = "Hello, world"; f(s);するために、テンプレート化されたフォームを呼び出す必要はありません。これsは、変数になり、コンパイル時の定数ではなくなったためです。

この質問の有用なケースは、最適化printfです。ほとんどの場合、formatは文字列リテラルになるため、実行時に を解析する代わりに、コンパイル時に多くのことをformat実行して最適化できます。

4

3 に答える 3

17

いいえ、文字列リテラルのような"foo"const char[S + 1]S、書いた文字数です。特別な規則のないその型の配列のように動作します。

C++03 では、文字列リテラルを に変換できるという特別な規則がありましたchar*。それはあなたが言うことを可能にしました

#define isStringLiteral(X) \
  isConvertibleToCharStar(X) && hasTypeConstCharArray(X)

たとえば、isStringLiteral(+"foo")yield false、およびisStringLiteral("foo")yield true になります。この可能性があっても、文字列リテラル引数を使用して関数を呼び出し、異なる動作をすることはできませんでした。

C++11 では、その特別な変換規則が削除され、文字列リテラルは他の配列と同様に動作します。C++11 では、汚いハックとしていくつかのマクロを作成し、エスケープ シーケンスを処理せずにいくつかの単純な文字列リテラルに一致させることができます。

constexpr bool isStringLiteral(const char *x, int n = 0) {
  return *x == '"' ? 
           n == 0 ?
             isStringLiteral(x + 1, n + 1)
             : !*(x + 1) 
           : (*x && n != 0 && isStringLiteral(x + 1, n + 1));
}

#define FastFun(X) \
  (isStringLiteral(#X) ? fConstExpr(X, sizeof(X) - 1) : f(X))
于 2013-02-17T20:24:01.307 に答える
0

私はこれをテストしていませんが、関数 constexpr を宣言して高度な最適化でコンパイルすると、コンパイラは可能な限りコンパイル時に計算を行うと思います。おまけとして、コードを 2 回記述する必要はありません。一方、constexpr スタイルでは一度記述する必要があります。

于 2013-02-18T18:36:16.017 に答える
-2

質問を正しく理解していれば、実際には関数のオーバーロードを使用してこのようなことが可能だと思います。 基本的な考え方を示した記事を次に示します。あなたの場合、次の 2 つのオーバーロードがあれば十分だと思います。

void f(char const *);

template<unsigned int N>
void f(char const (&)[N]);

文字列が文字列リテラルの場合は後者を呼び出し、それ以外の場合は後者を呼び出します。コンパイラが最適化に十分に長けている場合、後者への呼び出しはコンパイル時に評価される場合があります。

編集:

さて、上記の解決策がうまくいかないことが気になったので、いろいろ試してみたところ、解決策を思いついたと思います。

#include <string>
#include <boost/utility/enable_if.hpp>

template<typename T>
struct is_string_literal {
  enum { value = false };
};

template<unsigned int N>
struct is_string_literal<char const (&)[N]> {
   enum { value = true };
};

template<typename T>
typename boost::disable_if<is_string_literal<T> >::type
foo(T) {
  std::cout << "foo1" << std::endl;
}

template<int N>
void foo(char const (&)[N]) {
  std::cout << "foo2" << std::endl;
}

int main( ) {
  std::string bar = "blah";
  char const str[] = "blah";

  foo(str);
  foo("blah");

  foo(bar.data());
}

出力 (-O3 を指定した GCC 4.4 の場合) は次のとおりです。

foo2
foo2
foo1

以前のソリューションでは機能しなかったのに、なぜこれが機能するのか完全には理解できていないことを認めます。過負荷の解決について、私が完全に理解していないことがあるかもしれません。

于 2013-02-17T20:45:35.627 に答える