Ура, еще один вопрос, состоящий из случайной последовательности терминов C ++!
Обычно мы делаем класс Callable, реализуя operator()
. Но вы также можете сделать это, реализовав определяемое пользователем преобразование в указатель на функцию или ссылочный тип. Вместо использования идеальной пересылки функция преобразования может возвращать указатель на функцию, которая затем вызывается с исходным списком аргументов.
struct call_printf {
typedef int printf_t( char const *, ... );
operator printf_t & () { return std::printf; }
};
Насколько я могу судить, typedef
выше является синтаксической необходимостью. Имя функции преобразования формируется из type-specificier-seq, что не позволяет использовать такие конструкции, как int (*)()
. Для этого потребуется abstract-declarator. По-видимому, причина в том, что такие имена типов усложняются, а сложные конструкции, используемые в качестве имен объектов, трудно анализировать.
Функции преобразования также могут быть шаблонными, но аргументы шаблона должны быть выведены, потому что их негде явно указать. (Это лишило бы смысла неявное преобразование.)
Вопрос №1: В C ++ 03 не было возможности указать шаблон оператора преобразования функции? Похоже, что не было способа разрешить аргументы шаблона (то есть назвать их в выведенном контексте) в приемлемый тип указателя функции.
Вот эквивалентная ссылка из C ++ 11, §13.3.1.1.2 / 2 [over.call.object]. По сути, это то же самое, что и в C ++ 03:
Кроме того, для каждой неявной функции преобразования, объявленной в T формы
operator conversion-type-id () cv-qualifier attribute-specifier-seqopt;
где cv-qualifier - это то же cv-квалификация, что и, или большее cv-qualification, чем, cv, и где conversion-type-id < / em> обозначает тип «указатель на функцию (P1, ..., Pn), возвращающую R» или тип «ссылка на указатель на функцию (P1, ..., Pn), возвращающую R» , или тип «ссылка на функцию (P1, ..., Pn), возвращающую R», суррогатная функция вызова с уникальным именем call-function и имеющая форму
R call-function ( conversion-type-id F, P1 a1, ... ,Pn an) { return F (a1,... ,an); }
также рассматривается как функция-кандидат. Точно так же суррогатные функции вызова добавляются к набору функций-кандидатов для каждой неявной функции преобразования, объявленной в базовом классе T, при условии, что функция не скрыта внутри T другим промежуточным объявлением.
Вопрос № 2: Можно ли в C ++ 11 указать такое преобразование с помощью аргумента шаблона по умолчанию? Это полезно для SFINAE. Единственное отличие здесь от приведенного выше примера состоит в том, что идентификатор-типа-преобразования представляет только ссылку на функцию после создания экземпляра, поскольку это зависимый тип (несмотря на неизменность). Это запускает GCC и пропускает шаблон участника.
enum { call_alternate = true; }
struct call_switch {
template< bool en = call_alternate >
operator typename std::enable_if< en, decltype( fn_1 ) & >::type ()
{ return fn_1; }
template< bool en = ! call_alternate >
operator typename std::enable_if< en, decltype( fn_2 ) & >::type ()
{ return fn_2; }
};
У нас также есть шаблоны псевдонимов. Кажется, что подстановка псевдонима происходит до создания экземпляра, учитывая пример в §14.5.7 / 2, где объявления process
конфликтуют. В GCC 4.7 этот код, по крайней мере, создает экземпляр объявления, но затем выдает причудливую ошибку «кандидат ожидает 2 аргумента, 2 предоставлено».
template< typename t >
using fn_t = void (&)( t );
struct talk {
template< typename t >
operator fn_t< t >() { return fn; }
};
int main() {
talk()( 3 );
}
add_template_conv_candidate
, которая кажется недоступной из-за синтаксических особенностей. Итак, я хочу понять этот темный уголок языка. - person Potatoswatter   schedule 13.06.2012