我有以下代码:
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?
发布评论
评论(1)
不,您的理解是不正确的。
首先,名称不能同时引用类模板和函数模板。如果发生这种情况,该程序是不形成的。 (并且不允许在同一范围内定义这两个
。它是函数 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 ais_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 thatis_callable
is a class template and then realizes thatis_callable<Lambda>
is therefore a type. If you have a type, let's shorten it toT
, thenT()
can either be syntax representing the type of a function returningT
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 thenis_callable<Lambda>
is not a type and thereforeis_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. Andis_callable<Lambda>()
is a funcational notation explicit cast becauseis_callable<Lambbda>
is a type. Ifis_callable
was a function template instead of a class template, then it would be a function call.