2013-03-29 3 views
5

я должен написать тот же код зависит от времени компиляции постоянным параметром, что-то вроде:Macro повторить почти тот же код

map["text 0"] = vec[0]; 
map["text 1"] = vec[1]; 
... 
map["text n"] = vec[n]; 

Проблема заключается в том, что я не знаю n, когда я пишу код , Я получаю его как параметр шаблона. Очевидное решение состоит в том, чтобы использовать один цикл и сгенерировать "text k" внутри цикла и использовать vec[k], но это имеет накладные расходы во время выполнения, когда это необходимо сделать во время компиляции. Другим решением было бы специализировать функцию для разных значений N, но таким образом мне придется писать один и тот же код вручную несколько раз, и нет причин для его создания.

Я знаю, что есть некоторые умные макросы, которые могут повторять подобные вещи N раз (например, BOOST_PP_REPEAT macro family), но я не могу найти решение для моей конкретной проблемы.

У вас есть решение проблемы?

+0

Можно ли использовать C++ 11? – jrok

+0

@jrok Да, но не все функции (VS2010 и последний Xcode) – Felics

+0

Шаблоны и петли, вероятно, могут быть оптимизированы компилятором. –

ответ

4

Если у вас действительно есть действительно жесткие ограничения производительности, нет причин беспокоиться о нехватке времени выполнения. В любом случае вставки будут выполняться во время выполнения, и время вставки, безусловно, будет доминировать над временем, необходимым для изменения символа в строке.

Кроме того, макросы трудно отлаживать и поддерживать: избегайте их, если это возможно. Здесь я хотел бы предложить раскатать простой цикл:

std::string s = "text 0"; 
std::map<std::string, int> m; 
for (int i = 0; i < N; i++) 
{ 
    m[s] = vec[i]; 
    s[5] = '1' + i; // This is going to be the run-time overhead... 
} 

Если ваши цифры растут выше, чем 9, в C++ 11 вы можете использовать функцию to_string() для преобразования целого числа в строку:

std::string const s = "text "; 
std::map<std::string, int> m; 
for (int i = 0; i < N; i++) 
{ 
    m[s + std::to_string(i)] = vec[i]; 
} 

Если производительность окажется проблемой, вы можете попробовать более хардкорный подход на основе макросов. Однако, если ваши измерения не означают значительных накладных расходов, предпочитают простоту и ясность и разворачивают простой цикл.

+0

Это вызовет неопределенное поведение, я не могу изменить const char * - «текст 0» является const char *, даже если он не объявлен как const. – Felics

+1

@Felics: Строковый литерал '' text 0 "' имеет тип 'const char []', но это то, что вы используете для инициализации массива 'char', который может быть изменен. Вы не изменяете оригинальный литерал, поэтому здесь нет UB. И если ваш шаблон более сложный, вы можете использовать 'std :: string'. –

+0

Даже если вы объявляете его как не const, происходит преобразование из const в non const (принятое по стандарту 2003 года, не принятое к стандарту 2011 года). Также N может иметь более одной цифры. – Felics

0

Я считаю, что должно работать:

#include <boost/preprocessor.hpp> 
//... or just the required sub-headers 

// Will generate code for 0, 1, ... (N_END - 1) 
#define N_END 10 

#define ONE_ASSIGNMENT(maZ, maIter, maData) \ 
    if (maIter <= n) map["text " BOOST_PP_STRINGIZE(maIter)] = vec[maIter]; 

BOOST_PP_REPEAT(N_END, ONE_ASSIGNMENT, %%) //this generates the code 

#undef ONE_ASSIGNMENT 
#undef N_END 

Обратите внимание, что if() сравнивает литерал параметр шаблона (n), так что любой оптимизатор стоит его соли будет генерировать безфилиальный код из этого.

Я использую %% как «это значение никогда не используется». Он передается в аргумент maData, поэтому, если у вас есть что-то полезное для прохождения (например, "text "), вы можете сделать это вместо этого.

+0

Обратите внимание, что «n» принимается как параметр шаблона ... –

+0

@MatthieuM. Ага. Хорошо. Я даже полагаюсь на это, чтобы оптимизатор включил 'if()' только в тело или 'nop', поскольку он знает как литерал (' maIter'), так и константу времени компиляции ('n') в условии. Разумеется, код также будет работать без оптимизации (но это действительно просто устранение условий компиляции). – Angew

+0

Тогда я не совсем понимаю, почему '<= n', не должно быть' == n'? (Я не уверен, что понял вопрос ...) –

0

Повторение для меня не кажется проблемой, но преобразование int в строку и последующую конкатенацию выполняется во время компиляции. Проблема повторения может быть решена по следующей методике (непроверенных):

template<k,l> struct fill_vector { 
    static void doIt (... & vec) { 
     vec [INT_TO_TEXT (k)] = k; 
     fill_vector<k+1,l-1>::doIt (vec); 
    } 
}; 

template<k> struct fill_vector<k,0> { 
    static void doIt (... & vec) { 
     vec [INT_TO_TEXT (k)] = k; 
    } 
}; 

//... 

fill_vector<0,n>::doIt (vec); 

Может быть, кто-то идея, как реализовать INT_TO_TEXT

Смежные вопросы