Способы различения строкового литерала и строки, генерируемой во время выполнения

Предположим, у меня есть функция, которая принимает строку в качестве входных данных:

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

Решение

Нет, строковый литерал как "foo" имеет тип const char[S + 1] где S это количество символов, которое вы написали. Он ведет себя как массив такого типа без особых правил.

В C ++ 03 было специальное правило, которое гласило, что строковый литерал может преобразовываться в char*, Это позволило вам сказать

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

Например isStringLiteral(+"foo") даст false, а также isStringLiteral("foo") дал бы истину. Даже такая возможность не позволила бы вам вызывать функцию со строковым литеральным аргументом и вести себя по-другому.

C ++ 11 удалил это специальное правило преобразования, и строковые литералы ведут себя как любые другие массивы. В C ++ 11 как грязный хак вы можете составить несколько макросов, сопоставляя несколько простых строковых литералов без обработки escape-последовательностей.

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))
17

Другие решения

Хотя я не проверял это, я думаю, что если вы просто объявите функцию constexpr и скомпилируете с высокой оптимизацией, то компилятор будет вычислять во время компиляции всякий раз, когда это возможно. В качестве бонуса вам не нужно писать код дважды. С другой стороны, вы должны написать это один раз в стиле constexpr.

0

Если я правильно понимаю вопрос, я действительно думаю, что что-то подобное возможно с помощью перегрузки функции. Вот статья это показывает основную идею. В вашем случае я думаю, что было бы достаточно иметь следующие две перегрузки:

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

Выход (на GCC 4.4 с -O3):

foo2
foo2
foo1

Я признаю, что я не совсем понимаю, почему это работает, когда предыдущее решение не сработало. Может быть, есть кое-что о разрешении перегрузки, которое я не совсем понимаю.

-2
По вопросам рекламы [email protected]