В этом контексте я поеду на Inner Join. Если бы я использовал contains, он бы итерации 6 раз, несмотря на тот факт, что существует только одно совпадение.
var desiredNames = new[] { "Pankaj", "Garg" };
var people = new[]
{
new { FirstName="Pankaj", Surname="Garg" },
new { FirstName="Marc", Surname="Gravell" },
new { FirstName="Jeff", Surname="Atwood" }
};
var records = (from p in people join filtered in desiredNames on p.FirstName equals filtered select p.FirstName).ToList();
Предположим, у меня есть два объекта списка.
List 1 List 2
1 12
2 7
3 8
4 98
5 9
6 10
7 6
Используя Contains, он будет искать каждый элемент List 1 в списке 2, что означает, что итерация произойдет 49 раз !!!
Ну ... да, метапрограммирование шаблона не имеет побочных эффектов, поскольку оно предназначено. Я был введен в заблуждение от ошибок в более старых версиях GCC и немного неясной формулировки в Стандарте, чтобы полагать, что все эти функции возможны.
Однако, по крайней мере, функциональность области пространства имен может быть достигнута с небольшим использованием шаблонов. Функциональный поиск может извлекать числовое состояние из набора объявленных функций, как показано ниже.
Код библиотеки:
template< size_t n > // This type returns a number through function lookup.
struct cn // The function returns cn<n>.
{ char data[ n + 1 ]; }; // The caller uses (sizeof fn() - 1).
template< typename id, size_t n, size_t acc >
cn< acc > seen( id, cn< n >, cn< acc > ); // Default fallback case.
/* Evaluate the counter by finding the last defined overload.
Each function, when defined, alters the lookup sequence for lower-order
functions. */
#define counter_read( id ) \
( sizeof seen( id(), cn< 1 >(), cn< \
( sizeof seen( id(), cn< 2 >(), cn< \
( sizeof seen( id(), cn< 4 >(), cn< \
( sizeof seen( id(), cn< 8 >(), cn< \
( sizeof seen( id(), cn< 16 >(), cn< \
( sizeof seen( id(), cn< 32 >(), cn< 0 \
/* Add more as desired; trimmed for Stack Overflow code block. */ \
>() ).data - 1 ) \
>() ).data - 1 ) \
>() ).data - 1 ) \
>() ).data - 1 ) \
>() ).data - 1 ) \
>() ).data - 1 )
/* Define a single new function with place-value equal to the bit flipped to 1
by the increment operation.
This is the lowest-magnitude function yet undefined in the current context
of defined higher-magnitude functions. */
#define counter_inc( id ) \
cn< counter_read( id ) + 1 > \
seen( id, cn< ( counter_read( id ) + 1 ) & ~ counter_read( id ) >, \
cn< ( counter_read( id ) + 1 ) & counter_read( id ) > )
Быстрая демонстрация ( см. Прогон ):
struct my_cnt {};
int const a = counter_read( my_cnt );
counter_inc( my_cnt );
counter_inc( my_cnt );
counter_inc( my_cnt );
counter_inc( my_cnt );
counter_inc( my_cnt );
int const b = counter_read( my_cnt );
counter_inc( my_cnt );
#include <iostream>
int main() {
std::cout << a << ' ' << b << '\n';
std::cout << counter_read( my_cnt ) << '\n';
}
Ниже приведена версия, использующая C ++ 11 constexpr
вместо sizeof
.
#define COUNTER_READ_CRUMB( TAG, RANK, ACC ) counter_crumb( TAG(), constant_index< RANK >(), constant_index< ACC >() )
#define COUNTER_READ( TAG ) COUNTER_READ_CRUMB( TAG, 1, COUNTER_READ_CRUMB( TAG, 2, COUNTER_READ_CRUMB( TAG, 4, COUNTER_READ_CRUMB( TAG, 8, \
COUNTER_READ_CRUMB( TAG, 16, COUNTER_READ_CRUMB( TAG, 32, COUNTER_READ_CRUMB( TAG, 64, COUNTER_READ_CRUMB( TAG, 128, 0 ) ) ) ) ) ) ) )
#define COUNTER_INC( TAG ) \
constexpr \
constant_index< COUNTER_READ( TAG ) + 1 > \
counter_crumb( TAG, constant_index< ( COUNTER_READ( TAG ) + 1 ) & ~ COUNTER_READ( TAG ) >, \
constant_index< ( COUNTER_READ( TAG ) + 1 ) & COUNTER_READ( TAG ) > ) { return {}; }
#define COUNTER_LINK_NAMESPACE( NS ) using NS::counter_crumb;
template< std::size_t n >
struct constant_index : std::integral_constant< std::size_t, n > {};
template< typename id, std::size_t rank, std::size_t acc >
constexpr constant_index< acc > counter_crumb( id, constant_index< rank >, constant_index< acc > ) { return {}; } // found by ADL via constant_index
Объявления должны помещаться внутри пространства имен, а все имена, используемые в макросах, кроме counter_crumb
, должны быть полностью квалифицированный. Шаблон counter_crumb
найден через ассоциацию ADL с типом constant_index
.
Макрос COUNTER_LINK_NAMESPACE
можно использовать для увеличения одного счетчика в области нескольких пространств имен.
Поскольку совместная работа ухаживает, и я провел несколько часов, играя с базовым примером , это сторона, я также опубликую свое решение.
Связанная версия в статье есть два основных недостатка. Максимальное количество, которое он может подсчитать, очень низкое, из-за малой глубины рекурсии (обычно около 256). И время, затрачиваемое на компиляцию, как только подсчет более нескольких сотен был достигнут, огромен.
Реализовав двоичный поиск, чтобы определить, установлен ли флаг для счетчика или нет, можно увеличить максимальное количество (контролируемое через MAX_DEPTH), а также улучшить время компиляции одновременно. =)
Пример использования:
static constexpr int a = counter_id();
static constexpr int b = counter_id();
static constexpr int c = counter_id();
#include <iostream>
int main () {
std::cout << "Value a: " << a << std::endl;
std::cout << "Value b: " << b << std::endl;
std::cout << "Value c: " << c << std::endl;
}
Полностью рабочий код с примером в конце: (За исключением clang. См. комментарии.)
// Number of Bits our counter is using. Lower number faster compile time,
// but less distinct values. With 16 we have 2^16 distinct values.
#define MAX_DEPTH 16
// Used for counting.
template<int N>
struct flag {
friend constexpr int adl_flag(flag<N>);
};
// Used for noting how far down in the binary tree we are.
// depth<0> equales leaf nodes. depth<MAX_DEPTH> equals root node.
template<int N> struct depth {};
// Creating an instance of this struct marks the flag<N> as used.
template<int N>
struct mark {
friend constexpr int adl_flag (flag<N>) {
return N;
}
static constexpr int value = N;
};
// Heart of the expression. The first two functions are for inner nodes and
// the next two for termination at leaf nodes.
// char[noexcept( adl_flag(flag<N>()) ) ? +1 : -1] is valid if flag<N> exists.
template <int D, int N, class = char[noexcept( adl_flag(flag<N>()) ) ? +1 : -1]>
int constexpr binary_search_flag(int, depth<D>, flag<N>,
int next_flag = binary_search_flag(0, depth<D-1>(), flag<N + (1 << (D - 1))>())) {
return next_flag;
}
template <int D, int N>
int constexpr binary_search_flag(float, depth<D>, flag<N>,
int next_flag = binary_search_flag(0, depth<D-1>(), flag<N - (1 << (D - 1))>())) {
return next_flag;
}
template <int N, class = char[noexcept( adl_flag(flag<N>()) ) ? +1 : -1]>
int constexpr binary_search_flag(int, depth<0>, flag<N>) {
return N + 1;
}
template <int N>
int constexpr binary_search_flag(float, depth<0>, flag<N>) {
return N;
}
// The actual expression to call for increasing the count.
template<int next_flag = binary_search_flag(0, depth<MAX_DEPTH-1>(),
flag<(1 << (MAX_DEPTH-1))>())>
int constexpr counter_id(int value = mark<next_flag>::value) {
return value;
}
static constexpr int a = counter_id();
static constexpr int b = counter_id();
static constexpr int c = counter_id();
#include <iostream>
int main () {
std::cout << "Value a: " << a << std::endl;
std::cout << "Value b: " << b << std::endl;
std::cout << "Value c: " << c << std::endl;
}
adl_flag
, не работает для clang. (Этот: class = char[noexcept( adl_flag(flag<N>()) ) ? +1 : -1]
) Если вы можете найти тот, который правильно возвращает тип, только если adl_flag(flag<N>)
уже определен, это будет работать.
– Chartas
9 August 2017 в 16:17
К сожалению, метапрограммирование шаблонов по существу является функциональным языком, и в этом виде отсутствуют глобальные переменные или изменяемое состояние, которое могло бы реализовать такой счетчик.
Или это?
blockquote >C ++ позволяет скомпилировать счетчики времени (т. е. без
__COUNTER__
,__LINE__
или других подходов, предложенных здесь ранее), а также для выделения и определения внутреннего уникального идентификатора int для каждого экземпляра шаблона. См. Решение v1 для счетчика, реализованного с метапрограммой шаблона с использованием цепочки выделенных идентификаторов и v2 для второго варианта использования. Оба решения являются ответами на «Как я могу генерировать плотные уникальные идентификаторы типов во время компиляции?» . Но задача имеет важное требование к единственному идентификатору.
__VA_ARGS__
и переменные макросы, чтобы передать ,
в качестве аргумента макроса, обрезая COMMA
.
– Potatoswatter
8 August 2013 в 07:41
__VA_ARGS__
отзыв! Я не хотел критиковать ваш ответ; даже если вы объяснили это, я не уверен, что у меня есть необходимые умственные способности. Если бы вы добавили еще несколько объяснений, я бы внимательно прочитал его.
– rendaw
8 August 2013 в 12:59
CounterLimit
в GetCount
и 3 * CounterLimit
в GetLCount. __COUNTER__
должен был только изменить видимость функции и переустановить шаблон. Я только что проверил, и CounterLimit может быть 250 без каких-либо проблем, поэтому я думаю, что изначально неправильно оценил рекурсию.
– rendaw
8 August 2013 в 13:04
Я собирался решить эту проблему довольно давно и придумал очень короткое чистое решение. По крайней мере, я заслужил один взлет, чтобы попробовать это. :))
После кода библиотеки достигается функциональность уровня пространства имен. то есть мне удастся реализовать counter_read
и counter_inc
; но не counter_inc_t
(который добавляется внутри функции, потому что классы template
не допускаются внутри функции)
template<unsigned int NUM> struct Counter { enum { value = Counter<NUM-1>::value }; };
template<> struct Counter<0> { enum { value = 0 }; };
#define counter_read Counter<__LINE__>::value
#define counter_inc template<> struct Counter<__LINE__> { enum { value = Counter<__LINE__-1>::value + 1}; }
Этот метод использует метапрограммирование шаблона и использует макрос __LINE__
. См. результат для кода из вашего ответа.
Я считаю, что как MSVC, так и GCC поддерживают токен препроцессора __COUNTER__
, который на его месте заменяет монотонно увеличивающееся значение.
duodecilliotonically
, если я получу свои префиксы правильно ...: P
– Luis Machuca
22 March 2012 в 05:35
Вы можете использовать BOOST_PP_COUNTER
из Boost.Preprocessor.
Преимущество: он работает даже для макросов
Недостаток: есть только один счетчик вид "для всей программы, но механизм может быть переопределен для выделенных счетчиков
cn<N>
может быть дополнена по усмотрению компилятора. Таким образом,sizeof( cn<N> )
может быть любым значением & gt; = N. Требуется использоватьsizeof( cn<N>::data )
. – Cheers and hth. - Alf 8 April 2016 в 15:46__COUNTER__
) устраняет проблему заказа включения. Если нумерация файлов заголовков является целью, то пользователь должен знать о согласованности между TU. – Potatoswatter 9 April 2016 в 04:01