调用函数类型别名而不是函数

Calling function type alias instead of function

提问人:vtm11 提问时间:8/28/2023 最后编辑:Jan Schultkevtm11 更新时间:8/28/2023 访问量:114

问:

请考虑以下代码:

#include <iostream>

using f = void(std::string);

void fcorrect(f func, std::string s) {
    func(s); // calling function
};

void fmistake(f func, std::string s) {
    f(s); // calling type alias instead of function
};

void myprint(std::string s) {
    std::cout << s << std::endl;
};

int main() {
    std::string s = "message";
    fcorrect(myprint, s);
    fmistake(myprint, s);
    return 0;
}

函数接收函数和字符串作为参数,并按预期打印此字符串。 函数包含一个故意的错误 - 它调用类型别名而不是函数。它什么都不打印。fcorrectmyprintfmistakeffunc

我想知道当后一个函数调用发生时,引擎盖下发生了什么?也就是说,为什么没有抛出编译时或运行时错误?

C++ GCC 语言律师 类型别名编译 器错误

评论

6赞 Igor Tandetnik 8/28/2023
f(s)是一个声明,等效于(允许使用冗余括号)。这反过来又等价于 ,一个名为 的函数的正向声明。f s;void s(std::string);s
1赞 Igor Tandetnik 8/28/2023
@HolyBlackCat 事实并非如此。演员表不会编译。不能将 a 强制转换为函数类型。此外,您可以在那里放置任何其他名称,例如,它仍然可以编译std::stringf(xyz);
1赞 HolyBlackCat 8/28/2023
我纠正了。
2赞 康桓瑋 8/28/2023
我不认为重新定义为不同类型的符号是允许的。Clang 和 MSVC 都会拒绝您的代码s
2赞 Igor Tandetnik 8/28/2023
@PaulSanders 什么意思?的类型是 - 一个函数,接受和返回。sfstd::stringvoid

答:

3赞 Jan Schultke 8/28/2023 #1

正如评论者所说,是一个声明。关键的措辞在这里:f(s)

在涉及表达式语句和声明的语法中存在歧义:以函数式显式类型转换作为其最左边子表达式的表达式语可能与第一个声明符以 . 在这些情况下,该声明被视为声明,但以下规定除外。(

[ 示例 2:

class T { /* [...] */ };
// [...]
T(a);   //  declaration
// [...]

-- 结束示例 ]

- [stmt.ambig] 第 1 页

类型是什么(类、函数等)并不重要,如果命名一个类型,则是一个声明。T(a)T

该声明在这里不执行任何操作,因为它未被使用,并且等效于 或 。 在这种情况下已经是一个函数参数,所以 GCC 允许它是错误的。GCC 还允许:f(s)f svoid s(std::string)sstd::string s

void fmistake(f func, std::string s) {
    void s(std::string);
}

// GCC also allows the following (in C++ mode)
void foo(int x) {
    // GCC rejects this as re-declaring a symbol in C, but not in C++ mode.
    void x(int);
}

这是一个已知的 GCC 错误 52953,于 2012 年首次报告。

评论

0赞 vtm11 9/3/2023
看来砂轮终于开始运转