Похоже, что окна все еще пытаются копировать, когда вы нажимаете Ctrl + C, когда элемент выбран, и он, очевидно, получает представление toString () того, что выбрано. Я переместил код копирования в keyReleased () вместо keyPressed (), и теперь он работает как положено
Хороший компилятор должен сделать развертывание за вас. Например, при компиляции gcc с параметром -O2 включается циклическое развертывание.
Если вы попытаетесь сделать это вручную, если вы не будете тщательно измерять вещи и не будете точно знать, что вы делаете, вы в конечном итоге будете иметь более медленный код. Например, в вашем случае с ручным развертыванием вы обязаны помешать компилятору выполнить циклический обмен или оптимизацию стримина (ищите --floop-interchange и -floop-strip-mine в gcc docs )
Вы можете использовать Повышение MPL .
Пример развертывания цикла приведен на этой странице mpl :: for_each .
for_each< range_c<int,0,10> >( value_printer() );
Не похоже, что все это оценивается во время компиляции, но это может быть хорошей отправной точкой.
Ознакомьтесь с шаблонными метапрограммами и реализациями пузырьковой сортировки .
f
нужно будет вернуть double
- это невозможно сделать во время компиляции.
Я никогда не пытался сделать это, поэтому возьмите эту идею с крошкой соли ...
Похоже, что вы можете использовать Boost.Preprocessor , чтобы развернуть цикл (в частности, макросы BOOST_PP_FOR и BOOST_PP_FOR_r ), а затем использовать шаблоны для генерации фактическое константное выражение.
This is the way to do it directly:
template <int i, int j>
struct inner
{
static void value()
{
A(row<i,j>::value, column<i,j>::value) = f<i,j>::value;
inner<i, j+1>::value();
}
};
template <int i> struct inner<i, J> { static void value() {} };
template <int i>
struct outer
{
static void value()
{
inner<i, 0>::value();
outer<i+1>::value();
}
};
template <> struct outer<I> { static void value() {} };
void test()
{
outer<0>::value();
}
You can pass A
through as a parameter to each of the value
s if necessary.
Here's a way with variadic templates that doesn't require hard coded I and J:
#include <utility>
template <int j, class Columns>
struct Inner;
template <class Columns, class Rows>
struct Outer;
template <int j, int... i>
struct Inner<j, std::index_sequence<i...>>
{
static void value() { (A(column<i, j>::value, row<i, j>::value), ...); }
};
template <int... j, class Columns>
struct Outer<std::index_sequence<j...>, Columns>
{
static void value() { (Inner<j, Columns>::value(), ...); }
};
template <int I, int J>
void expand()
{
Outer<std::make_index_sequence<I>, std::make_index_sequence<J>>::value();
}
void test()
{
expand<3, 5>();
}
(snippet with generated assembly: https://godbolt.org/g/DlgmEl)
Вы можете использовать Boost.Mpl для реализации всего этого во время компиляции, но я не уверен, что это будет быстрее. (Mpl по существу повторно реализует все алгоритмы STL в виде шаблонов метапрограммирования времени компиляции)
Проблема с этим подходом состоит в том, что вы в конечном итоге разворачиваете и встраиваете много кода, что может разрушить кэш инструкций. и съедают пропускную способность памяти, которую можно было бы сэкономить. Это может привести к появлению огромного, раздутого и медленного кода.
Я, вероятно, предпочел бы доверять компилятору встроить функции, которые имеют смысл. Пока определения функций row
и столбец
видны из цикла, компилятор может просто встроить вызовы и развернуть столько итераций, сколько сочтет полезным.
Я бы сказал, что это ложная хорошая идея.
В C ++ это:
row :: value
означает, что у вас будет столько разных функций row <> ()
, чем у вас i * j. Вы этого не хотите, потому что это увеличит размер кода и приведет к множеству пропусков кеша инструкций.
Я наблюдал это, когда выполнял функции шаблона, чтобы избежать единственной логической проверки.
Если это короткая функция, просто вставьте ее.
Я не фанат метапрограммирования шаблонов, поэтому вы можете отнестись к этому ответу с долей скепсиса. Но, прежде чем я потратил сколько-нибудь времени на решение этой проблемы, я бы спросил себя следующее:
for
узким местом? Во многих компиляторах / процессорах "зацикленная" версия может дать лучшую производительность из-за эффектов кеширования.
Помните: сначала измеряйте, затем оптимизируйте - если вообще.
Если вы хотите немного изменить синтаксис, вы можете сделать что-то вроде этого:
template <int i, int ubound>
struct OuterFor {
void operator()() {
InnerFor<i, 0, J>()();
OuterFor<i + 1, ubound>()();
}
};
template <int ubound>
struct OuterFor <ubound, ubound> {
void operator()() {
}
};
В InnerFor i - счетчик внешних циклов (константа времени компиляции), j - внутренние циклы counter (изначально 0 - также константа времени компиляции), поэтому вы можете оценить row как шаблон времени компиляции.
Это немного сложнее, но, как вы говорите, row (), col () и f () - это ваши в любом случае сложные детали. По крайней мере, попробуйте и посмотрите, стоит ли оно того. Возможно, стоит изучить другие варианты упрощения функций row () и т. Д.