当我在模板参数中投射时,为什么函数呼叫将其视为实例化?

发布于 2025-02-13 05:03:14 字数 1375 浏览 1 评论 0 原文

我有以下代码:

template <bool condition>
struct enable_if { };

template <>
struct enable_if<true> { using type = bool; };

template <typename T>
class is_callable {
    using Yes = char[1];
    using No = char[2];

    template <typename U> static Yes& filter(decltype(&U::operator()));
    template <typename U> static No& filter(...);

public:
    constexpr operator bool() { return sizeof(filter<T>(nullptr)) == sizeof(Yes); }
};

template <typename Lambda, typename enable_if<is_callable<Lambda>{}>::type = true>
void doSomethingWithLambda(Lambda func) {
    func();
}

int main() {
    doSomethingWithLambda([]() { });
}

重要的部分是 enable_if; iS_callable&lt; lambda&gt; {}}&gt; :: type part。 有人被迫实例化 is_callable&lt; lambda&gt; 带有 {} ,因为如果有人使用(),C ++会将其误认为是函数调用。

如果我错了,请随时纠正我,但据我所知,C ++认为它是()案例中的功能,以便在表达式之后确定表达式的类型写作,为所有人节省头痛。我的意思是,假设您有一个函数版本和 is_callable 的类版本(使用 enable_if 或沿这些行的某些东西,由Sfinae分隔),则类型Lambda可以确定()的真实含义,无论是函数调用还是实例化。就像我说的那样,据我所知,C ++希望避免这种混乱,因此,如果不存在此类函数,它会假定函数调用,并且失败。

基于上面的假设,以下内容不应起作用:

enable_if<(bool)is_callable<Lambda>()>::type

如果我施放函数呼叫的结果,这有什么关系(不要介意在此上下文中无法评估函数)?为什么突然将其视为实例化而不是功能调用?

I've got the following code:

template <bool condition>
struct enable_if { };

template <>
struct enable_if<true> { using type = bool; };

template <typename T>
class is_callable {
    using Yes = char[1];
    using No = char[2];

    template <typename U> static Yes& filter(decltype(&U::operator()));
    template <typename U> static No& filter(...);

public:
    constexpr operator bool() { return sizeof(filter<T>(nullptr)) == sizeof(Yes); }
};

template <typename Lambda, typename enable_if<is_callable<Lambda>{}>::type = true>
void doSomethingWithLambda(Lambda func) {
    func();
}

int main() {
    doSomethingWithLambda([]() { });
}

The important part is the enable_if<is_callable<Lambda>{}>::type part.
One is forced to instantiate is_callable<Lambda> with {} because if one were to use (), C++ would mistake it for a function call.

Feel free to correct me if I'm wrong, but as far as I know, C++ assumes it is a function in the () case so that the type of expression isn't determined after the time of writing, saving everyone a headache. What I mean by that is, assuming you had a function version and a class version of is_callable (separated by SFINAE using enable_if or something along those lines), the type Lambda could determine the true meaning of (), either a function call or an instantiation. Like I said, as far as I know, C++ wants to avoid this confusion, so it assumes function call and fails if such a function does not exist.

Based on the assumptions above, the following shouldn't work:

enable_if<(bool)is_callable<Lambda>()>::type

What does it matter if I cast the result of the function call (never mind that functions couldn't even be evaluated in this context)? Why is this suddenly treated as an instantiation instead of a function call?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

小…楫夜泊 2025-02-20 05:03:14

不,您的理解是不正确的。

首先,名称不能同时引用类模板和函数模板。如果发生这种情况,该程序是不形成的。 (并且不允许在同一范围内定义这两个

。它是函数 type 。它是没有参数并返回a is_callable&lt; lambda&gt; 的函数的类型。

当编译器解析模板参数时,它可以通过两种方式解释:作为一种类型或表达式(或作为支撑式列表),因为模板参数可以是类型参数或非类型参数。

当编译器读取 is_callable&lt; lambda&gt;()时,它注意到 is_callable 是类模板,然后意识到 is_callable&lt; lambda&gt; 因此类型。如果您有类型,让我们将其缩短到 t ,那么 t()可以是代表函数的 type 的语法,返回 > t 不进行任何参数,也可以是由一个单个功能符号显式铸造形成的表达式(您不确定地称为“实例化”)。

在上下文中无法区分这两种情况,但是编译器需要知道这是类型的模板参数还是非类型模板参数。因此,有一条规则说,这种歧义总是有利于一种类型的解决方案。

如果 is_callable 是函数模板,则不会有歧义,因为 is_callable&lt; lambda&gt; 不是类型,因此 iS_callable&lt; lambda&gt;(()<(()<()<()<()<()<()<()<()<()<()<()<()<()<()<()<()<()<()<() /代码>不能是函数类型。它必须是函数调用,因此是表达式和​​非类型模板参数。

当您编写(bool)is_callable&lt; lambda&gt;()这不是一种类型的有效语法,因此没有歧义。这是一个非型模板参数和一个表达式。和 is_callable&lt; lambda&gt;()是一种弹性符号,因为 is_callable&lt; lambbda&gt; 是一种类型。如果 is_callable 是函数模板而不是类模板,则将是函数调用。

No, your understanding is not correct.

Firstly, a name can't refer to both a class template and a function template. If that happens the program is ill-formed. (And defining both in the same scope is not allowed to begin with.)

Secondly, is_callable<Lambda>() as template argument is not a function call to begin with. It is a function type. It is the type of a function which has no parameters and returns a is_callable<Lambda>.

When the compiler parses a template argument, it can interpret it in two ways: Either as a type or as an expression (or as a braced-init-list), because template parameters can be type parameters or non-type parameters.

When the compiler reads is_callable<Lambda>() it notices that is_callable is a class template and then realizes that is_callable<Lambda> is therefore a type. If you have a type, let's shorten it to T, then T() can either be syntax representing the type of a function returning T and taking no arguments, or it can be an expression formed from one single functional notation explicit cast (which you imprecisely call "instantiation").

There is no way to differentiate these two cases in the context, but the compiler needs to know whether this is a type template argument or a non-type template argument. So there is a rule saying that such ambiguities are always resolved in favor of a type.

If is_callable was a function template instead, there would be no ambiguity, because then is_callable<Lambda> is not a type and therefore is_callable<Lambda>() cannot be a function type. It must be a function call instead and therefore an expression and non-type template argument.

When you write (bool)is_callable<Lambda>() this is not valid syntax for a type and therefore there is no ambiguity. It is a non-type template argument and an expression. And is_callable<Lambda>() is a funcational notation explicit cast because is_callable<Lambbda> is a type. If is_callable was a function template instead of a class template, then it would be a function call.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文