2

Я пытаюсь играть в причудливые игры, в которых компилятор C++ синтезирует хеш-значения постоянных строк в compiletime. Это позволило бы мне заменить строку одним идентификатором, с огромной экономией в размере и сложности кода.Является ли константа константы compiletime константным массивом compiletime самой константой compiletime?

Для ясности и простоты программирования было бы замечательно, если бы я мог исследовать и вычислять в compiletime с помощью простых встроенных символов, таких как «Hello», которые являются постоянными указателями compileime для постоянных символов compiletime.

Если я могу указать их в compiletime, я могу создать метапрограмму шаблона, чтобы делать то, что я хочу. Но неясно, относится ли стандарт C++ к константе ct-константы массива ct-констант как константа ct-константа.

Спросил еще один способ,

const char v="Hello"[0]; 

вполне действительный C++ (и C). Но - это значение v константа времени компиляции?

Я уже считаю, что ответ отрицательный, но на практике некоторые компиляторы принимают его без какого-либо предупреждения, а тем более ошибки. Например, следующие компилируется и работает без единого предупреждения от компилятора C++ от Intel:

#include <iostream> 
const char value="Hello"[0]; 
template<char c> void printMe() 
{ 
    std::cout << "Template Val=" << c << std::endl; 
} 

int main() 
{ 
    const char v='H'; 
    printMe<'H'>(); 
    printMe<v>(); 
    printMe<value>(); // The tricky and interesting case! 
} 

Однако компилятор от Microsoft не будут компилировать на всех, давая сообщение достаточно когерентные ошибок об использовании шаблона с объектом с внутренним связь.

Я подозреваю, что ответ на мой вопрос: «Нет, вы не можете считать, что ссылка на массив даже в постоянном массиве с постоянным индексом постоянна в compiletime». Означает ли это, что успешное выполнение компилятора Intel является ошибкой в ​​компиляторе Intel?

ответ

2

Он также не работает на GCC.

Однако, за пределами точки зрения соответствия требованиям, приятно, что оптимизатор компилятора действительно относится к нему как к символьной константе. Я использовал этот факт, чтобы разрешить генерируемые препроцессором символьные константы (используя *#foo). См. http://cvs.openbsd.org/cgi-bin/query-pr-wrapper?full=yes&numbers=1652, в файле hdr.h. С этой макрокоманды, вы можете написать

DECR(h, e, l, l, o) 

, а не

DECR('h', 'e', 'l', 'l', 'o') 

Гораздо более удобным для чтения, на мой взгляд. :-)

+0

Clever макрос хак использовать оператор stringize макрос charize сырые символы! Конечно, это не помогает при попытке использовать аргумент шаблона. Если, может быть, макрос стиля varargs (C99 ??) может удалить один символ, построить новый typedef и включить остальные аргументы var в качестве рекурсивного типа a-la Loki? – SPWorley

1

Хорошего вопрос, да это может быть сделано, и его прекрасно стандартами, и она будет работать на Microsoft, GCC и Intel, проблема в том, у вас есть синтаксис неправильно :)

One второй я приготовлю образец ... Хорошо, вот оно. Этот пример действителен C++, и я использовал его довольно часто, но большинство программистов не знают, как правильно это сделать.

template<char* MSG> 
class PrintMe 
{ 
public: 
    void operator()() 
    { 
     printf(MSG); 
    } 
}; 

char MyMessage[6] = "Hello"; //you can't use a char*, but a char array is statically safe and determined at compiletime 

int main(int argc, char* argv[]) 
{ 
    PrintMe<MyMessage> printer; 
    printer(); 
    return 0; 
} 
+1

Это не доступ к DATA в compiletime, просто указатель char. Так, например, после принтера(); вы можете добавить MyMessage [0] ++; Принтер(); и вы увидите, что данные обновлены. Это означает, что к данным обращаются во время выполнения, а не в компиляцию. Но ваш пример по-прежнему интересен тем, что не константный указатель может быть передан как шаблонный аргумент. – SPWorley

+0

Это означает, что я не уверен, что вы хотели сделать, но если я смогу сделать это, вы можете сделать то, что хотите, можете ли вы дать лучшее объяснение ожидаемого поведения вашего последнего шаблона? –

+0

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

0

Соответствующая разница здесь заключается в различии между «интегральным постоянным выражением» и простой константой времени компиляции. «3.0» - это константа времени компиляции. «int (3.0)» также является константой времени компиляции. Но только «3» - это ICE. [См. 5.19]

More details at boost.org

+0

Спасибо за ссылку, но она, похоже, не применяется. В примере кода const char value = "Hello" [0]; определяет значение как интегральное постоянное выражение (как показывает страница Boost в качестве примера 3). Однако значение отклоняется как аргумент шаблона, поэтому интегральные константные выражения не являются константами компиляции, которые можно использовать в шаблонах. – SPWorley

+0

Хорошая точка, но не актуальная. Глобальная константа целочисленного типа - это ICE, если и только если она инициализирована самой ICE. Например, const char value = rand(); также не является ICE, но он также выглядит как пример 3 от Boost. Ваша проблема такая же: «Привет» [0] не является ICE, поэтому вы не можете инициализировать другие ICE. – MSalters