decltype(function_name)的返回类型完全没用?

时间:2018-03-02 15:27:25

标签: c++ function declaration decltype

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

根据decltype规则,decltype(foo)的类型应为&#34; void foo(int)&#34;, 但似乎我们无能为力:

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

6 个答案:

答案 0 :(得分:2)

声明变量:

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

使用std::function函数包装器:

std::function<decltype(foo)> f = foo;
f(42);

答案 1 :(得分:2)

您的摘要中的两个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;

不编译,因为您无法分配给函数。即使dfvoid df(int);,它也无效。

我该如何使用这种类型?

有无数的用途。例如。您可以使用它来创建如上所述的此函数的指针,或者它可以用作模板参数(对于std::function或其他内容)。

答案 2 :(得分:1)

您可以使用它来声明与函数具有相同签名的功能对象:

using ffoo = ::std::function<decltype(foo)>;

答案 3 :(得分:1)

  

decltype(function_name)的返回类型是否完全没用?

绝对不是。 Live example

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一起使用。

答案 4 :(得分:1)

在本声明中

package main

import (
    "bytes"
    "encoding/json"
    "fmt"
    "io/ioutil"
    "log"
    "net/http"
    "net/http/httputil"
)

type token struct {
    Token string
}

type config struct {
    Foo string
}

func main() {
    token, err := getAuthToken()
    if err != nil {
        log.Fatal(err)
    }

    config, err := getConfig("foo", token)
    if err != nil {
        log.Fatal(err)
    }

    _ = config
}

func getAuthToken() (string, error) {
    endpoint := "foo"

    body := struct {
        UserName string `json:"username"`
        Password string `json:"password"`
    }{
        UserName: "foo",
        Password: "bar",
    }
    var token token

    err := sendRequest(endpoint, body, &token)
    if err != nil {
        return "", err
    }

    return token.Token, nil
}

func getConfig(id string, token string) (*config, error) {
    endpoint := "foo"

    body := struct {
        ID string `json:"id"`
    }{
        ID: id,
    }
    var config config

    err := sendRequest(endpoint, body, &config, header("Content-Type", "application/json"))
    if err != nil {
        return nil, err
    }

    return &config, nil
}

type option func(*http.Request)
func header(key, value string) func(*http.Request) {
    return func(req *http.Request) {
        req.Header.Add(key, value)
    }
}

func sendRequest(endpoint string, body interface{}, result interface{}, options ...option) error {
    jsnBytes, err := json.Marshal(body)
    if err != nil {
        return err

    }

    req, err := http.NewRequest("POST", endpoint, bytes.NewReader(jsnBytes))
    if err != nil {
        return fmt.Errorf("Unable to create request. %v", err)

    }

    req.Header.Add("Content-Type", "application/json")
    for _, option := range options {
        option(req)
    }


    dump, err := httputil.DumpRequest(req, true)
    if err != nil {
        return fmt.Errorf("Could not dump request. ", err)
    }

    log.Println("Request: ", string(dump))

    client := http.Client{}
    log.Println("Initiating http request")

    resp, err := client.Do(req)
    if err != nil {
        return fmt.Errorf("HTTP Error: %v", err)
    }
    defer resp.Body.Close()

    bytes, err := ioutil.ReadAll(resp.Body)
    if err != nil {
        return fmt.Errorf("Error reading response body: %v", err)
    }

    err = json.Unmarshal(bytes, result)
    if err != nil {
        return fmt.Errorf("Could not unamrshal json. ", err)
    }
    return nil
}

左模板参数是函数类型,而右模板参数是引用类型。要比较类型,您应该删除引用。

在本声明中

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

将函数类型与指向函数的指针进行比较。

因此,both语句返回0(false)。

这些陈述

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

没有意义。您可能无法分配功能。

这些陈述

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; 被隐式转换为指向函数的指针。

答案 5 :(得分:-1)

这完全是应该的。如果你写了plt.scatter(df.x, df.y, s=150, c=df.Cat) ,那显然是错的。您正在尝试使用函数类型声明变量,这是没有意义的。唯一可能有意义的上下文是声明一个函数对象:void(int) df; 现在auto bar = std::function<decltype(foo)>;是一个对象,它引用类型为bar的函数(或类似函数的实例,例如lambda)。