gpt4 book ai didi

c++ - 为什么在没有参数的情况下调用省略号而不是可变参数模板?

转载 作者:IT老高 更新时间:2023-10-28 22:20:20 25 4
gpt4 key购买 nike

我正在使用以下 SFINAE 模式来评估可变参数类型列表上的谓词:

#include <type_traits>

void f(int = 0); // for example

template<typename... T,
typename = decltype(f(std::declval<T>()...))>
std::true_type check(T &&...);
std::false_type check(...);

template<typename... T> using Predicate = decltype(check(std::declval<T>()...));

static_assert(!Predicate<int, int>::value, "!!");
static_assert( Predicate<int>::value, "!!");
static_assert( Predicate<>::value, "!!"); // fails

int main() {
}

令我惊讶的是,省略号重​​载在 check 时被选中。使用空参数列表调用,所以 Predicate<>std::false_type即使 SFINAE 表达式有效!

不应该总是首选可变参数函数模板而不是省略号函数吗?

有什么解决方法吗?

最佳答案

T...为空时,编译器会执行重载解析来判断是哪一个

std::true_type check(); // instantiated from the function template
std::false_type check(...);

是最佳可行的候选者,如 [over.match.best] 13.3.3/1(引用 N3936)中所述:

Define ICSi(F) as follows:

  • if F is a static member function, ICS1 (F) is defined such that ICS1 (F) is neither better nor worse than ICS1 (G) for any function G, and, symmetrically, ICS1 (G) is neither better nor worse than ICS1 (F)132; otherwise,

  • let ICSi(F) denote the implicit conversion sequence that converts the i-th argument in the list to the type of the i-th parameter of viable function F. 13.3.3.1 defines the implicit conversion sequences and 13.3.3.2 defines what it means for one implicit conversion sequence to be a better conversion sequence or worse conversion sequence than another.

Given these definitions, a viable function F1 is defined to be a better function than another viable function F2 if for all arguments i, ICSi(F1) is not a worse conversion sequence than ICSi(F2), and then

  • for some argument j, ICSj(F1) is a better conversion sequence than ICSj(F2), or, if not that,

  • the context is an initialization by user-defined conversion (see 8.5, 13.3.1.5, and 13.3.1.6) and the standard conversion sequence from the return type of F1 to the destination type (i.e., the type of the entity being initialized) is a better conversion sequence than the standard conversion sequence from the return type of F2 to the destination type. [ Example:

    struct A {
    A();
    operator int();
    operator double();
    } a;
    int i = a; // a.operator int() followed by no conversion
    // is better than a.operator double() followed by
    // a conversion to int
    float x = a; // ambiguous: both possibilities require conversions,
    // and neither is better than the other

    end example ] or, if not that,

  • the context is an initialization by conversion function for direct reference binding (13.3.1.6) of a reference to function type, the return type of F1 is the same kind of reference (i.e. lvalue or rvalue) as the reference being initialized, and the return type of F2 is not [ Example:

    template <class T> struct A {
    operator T&(); // #1
    operator T&&(); // #2
    };
    typedef int Fn();
    A<Fn> a;
    Fn& lf = a; // calls #1
    Fn&& rf = a; // calls #2

    end example ] or, if not that,

  • F1 is not a function template specialization and F2 is a function template specialization, or, if not that,

  • F1 and F2 are function template specializations, and the function template for F1 is more specialized than the template for F2 according to the partial ordering rules described in 14.5.6.2.

在这种情况下,两个候选的转换序列都是空的,因为没有参数。倒数第二个项目符号是决定因素:

  • F1 is not a function template specialization and F2 is a function template specialization, or, if not that,

因此非模板 std::false_type check(...); 是首选。


我首选的解决方法 - 显然有很多 - 是通过省略号转换 [over.ics.ellipsis] 13.3.3.1.3/1 来制作候选模板并进行区分:

An ellipsis conversion sequence occurs when an argument in a function call is matched with the ellipsis parameter specification of the function called (see 5.2.2).

通过为“首选”模板声明提供一个明显更好匹配的无关参数,因为根据 [over.ics.rank] 13.3.3.2/2,任何其他转换序列都将优于省略号转换:

When comparing the basic forms of implicit conversion sequences (as defined in 13.3.3.1)

  • a standard conversion sequence (13.3.3.1.1) is a better conversion sequence than a user-defined conversion sequence or an ellipsis conversion sequence, and
  • a user-defined conversion sequence (13.3.3.1.2) is a better conversion sequence than an ellipsis conversion sequence (13.3.3.1.3).

Example :

template<typename... T,
typename = decltype(f(std::declval<T>()...))>
std::true_type check(int);
template<typename...>
std::false_type check(...);

template<typename... T> using Predicate = decltype(check<T...>(0));

关于c++ - 为什么在没有参数的情况下调用省略号而不是可变参数模板?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/23804312/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com