void foo(int a) {
    cout << "Hello" << a << '\n';
}

Согласно правилу decltype, тип decltype (foo) должен быть «void foo (int)», но, похоже, мы ничего не можем с этим поделать:

void (& f_ref)(int) = foo;
void (* f_ptr)(int) = foo;


cout<<is_same_v<decltype(foo), decltype(f_ref)><<endl; //return 0
cout<<is_same_v<decltype(foo), decltype(f_ptr)><<endl; //return 0
decltype(foo) df;
df = foo;    //error: assignment of function ‘void df(int)’
df = &foo;   //error: assignment of function ‘void df(int)’

decltype(foo) df{foo}; //error: function ‘void df(int)’ is initialized like a variable
decltype(foo) df{&foo}; //error: function ‘void df(int)’ is initialized like a variable
2
camino 2 Мар 2018 в 18:27

6 ответов

Лучший ответ

Два is_same_v в ваших фрагментах оцениваются как 0, потому что, ну, типы разные.

dectype(foo) - void (int) (не void foo(int), имя не является частью типа),
который отличается от void (&)(int) (тип f_ref) и void (*)(int) (тип f_ptr).


Эта строка:

decltype(foo) df{foo};

Не компилируется только потому, что синтаксис не позволяет иметь инициализаторы в объявлениях функций.

Даже без decltype это не работает:

void df(int) {foo}; // error: expected ';' before '}' token

Хотя вы можете создать указатель на decltype(foo):

decltype(foo) *df{foo}; // Becomes `void (*df)(int) {foo};`

Эти строки:

df = foo;
df = &foo;

Не компилировать, потому что вы не можете назначать функции. Это не сработает, даже если df был void df(int);.


Как я могу использовать этот тип?

Есть бесчисленное множество применений. Например. Вы можете использовать его для создания указателей на эту функцию, как упомянуто выше, или его можно использовать в качестве параметра шаблона (для std::function или чего-то еще).

2
HolyBlackCat 2 Мар 2018 в 15:57

Является ли возвращаемый тип decltype (имя_функции) полностью бесполезным?

Точно нет. Живой пример

void f1();
void f2(int);
void f3();

int main()
{
    std::cout << "f1 - f2 " << std::is_same<decltype(f1),decltype(f2)>::value << std::endl;
    std::cout << "f1 - f3 " << std::is_same<decltype(f1),decltype(f3)>::value << std::endl;
}

Это можно использовать с std::enable_if, например.

1
Slava 2 Мар 2018 в 15:45

Это именно так, как и должно быть. Если вы написали void(int) df;, это явно неправильно. Вы пытаетесь объявить переменную с типом функции, что не имеет смысла. Единственный контекст, в котором это может иметь смысл, - это объявить объект функции: auto bar = std::function<decltype(foo)>; Теперь bar является объектом, который ссылается на функцию (или подобный функции экземпляр, такой как лямбда) с типом void(int).

-1
Mikaela Szekely 2 Мар 2018 в 15:43

В этом заявлении

cout<<is_same_v<decltype(foo), decltype(f_ref)><<endl;

Левый аргумент шаблона является типом функции, в то время как правый аргумент шаблона является ссылочным типом. Для сравнения типов вы должны удалить ссылку.

В этом заявлении

cout<<is_same_v<decltype(foo), decltype(f_ptr)><<endl;

Сравнивается тип функции с указателем на функцию.

Таким образом, оба оператора возвращает 0 (ложь).

Эти заявления

df = foo; 
df = &foo;

Не имеет смысла. Вы не можете назначать функции.

И эти заявления

decltype(foo) df{foo}; 
decltype(foo) df{&foo};

Тоже не имеет смысла.

Вы можете объявить функцию типа decltype( foo ), например, в классе, а затем определить ее.

Вот демонстрационная программа.

#include <iostream>
#include <type_traits>

void foo( int a ) 
{
    std::cout << "Hello " << a << '\n';
}

struct A
{
    decltype(foo) df;
};

void A::df( int a )
{
    std::cout << "Bye " << a << '\n';
}

int main() 
{
    foo( 0 );
    A a;

    a.df( 1 );

    void (& f_ref)(int) = foo;
    void (* f_ptr)(int) = foo;

    std::cout << std::is_same<decltype(&foo), decltype( f_ptr )>() << std::endl;
    std::cout << std::is_same<decltype(foo), std::remove_reference_t<decltype( f_ref )>>() << std::endl;

    return 0;
}

Его вывод

Hello 0
Bye 1
1
1

Примите во внимание, что в этой декларации

void (& f_ref)(int) = foo;

Обозначение функции foo неявно преобразуется в указатель на функцию.

1
Vlad from Moscow 3 Мар 2018 в 10:13

Вы можете использовать его для объявления функционального объекта, который будет иметь ту же сигнатуру, что и функция:

using ffoo = ::std::function<decltype(foo)>;
1
user7860670 2 Мар 2018 в 15:39

Объявите переменную:

decltype(foo)* pf = foo;
pf(42);

Используйте std::function функциональную оболочку:

std::function<decltype(foo)> f = foo;
f(42);
2
Phil Brubaker 2 Мар 2018 в 15:44