Шаблонная функция преобразования в указатель на функцию

Ура, еще один заголовок вопроса, состоящий из случайной последовательности терминов C++!

Обычно мы делаем класс Callable, реализуя operator(). Но вы также можете сделать это, реализуя определяемое пользователем преобразование в указатель на функцию или ссылочный тип. Вместо использования идеальной переадресации функция преобразования может возвращать указатель на функцию, которая затем вызывается с исходным списком аргументов.

struct call_printf {
    typedef int printf_t( char const *, ... );
    operator printf_t & () { return std::printf; }
};

http://ideone.com/kqrJz

Насколько я могу судить, typedefвыше является синтаксической необходимостью. Имя функции преобразования формируется из type-specifier-seq, что не позволяет использовать такую ​​конструкцию, как int (*)(). Для этого потребуется abstract-declarator. Предположительно причина в том, что такие имена типов усложняются, а сложные конструкции, используемые в качестве имен объектов, трудно анализировать.

Функции преобразования также могут быть шаблонными, но аргументы шаблона должны быть выведены, потому что их негде явно указывать. (Это лишило бы смысла неявное преобразование.)


Вопрос №1:В C++03 не было способа указать шаблон оператора преобразования функции? Похоже, что не было способа разрешить аргументы шаблона (т. е. назвать их в выведенном контексте) в приемлемом типе указателя функции.

Вот эквивалентная ссылка из C++11, §13.3.1.1.2/2 [over.call.object]. По сути, это то же самое, что и в C++03:

Кроме того, для каждой функции неявного преобразования, объявленной в T в форме

, оператор convert-type-id () cv-qualifier attribute-specifier-seqopt;

где cv-qualifier— это та же cv-квалификация или более высокая cv-квалификация, чем cv, и где идентификатор типа преобразования обозначает тип «указатель на функцию (P1,...,Pn), возвращающую R», или тип «ссылка на указатель на функцию (P1,...,Pn), возвращающую R», или тип «ссылка на функцию из (P1,...,Pn), возвращающую R», суррогатную функцию вызова с уникальным именем call-function и имеющую форму

R call-function ( convert-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 );
}

8
задан Potatoswatter 13 June 2012 в 15:57
поделиться