C++:模板 模板参数的模板成员作为模板类的参数 需要模板 模板参数

标签 c++ templates c++20 template-templates

首先,对这个可怕的标题表示歉意。我正在尝试 C++20 is_detected功能。 is_detected基本上采用两个模板参数,一个是执行检查的高阶类型,另一个是要检查的类型。我在以下场景中遇到了问题:

#include <stdio.h>
#include <type_traits>

// kind of how std::experimental::is_detected is implemented
template <template <typename> typename Checker, typename T, typename = void>
struct is_detected: std::false_type {};

template <template <typename> typename Checker, typename T>
struct is_detected<Checker, T, std::void_t<Checker<T>>>: std::true_type {};

struct Foo {
    template <typename T>
    using Checker = decltype(std::declval<T>().foo());

    template <typename T>
    static constexpr void call(T &t) {
        t.foo();
    }
};

template <typename T>
using GlobalChecker = decltype(std::declval<T>().foo());

template <typename T>
struct Wrapper {
    template <typename U>
    using LocalChecker = typename T::template Checker<U>;
    //                               ^^^^^^^^ clang and msvc require template keyword
    //                                        gcc doesn't require it

    template <typename U>
    constexpr void conditional_call(U &u) const noexcept {
        if constexpr (
            is_detected<
                typename T::Checker,// !!! COMPILE ERROR !!!
                                    // works for
                                    // GlobalChecker,
                                    // LocalChecker and
                                    // Foo::Checker, though.
                std::decay_t<U>>
                ::value) {
            Foo::call(u);
        }
        else {
            puts("fallback");
        }
    }
};

int main() {
    struct {
        void foo() {
            puts("heyy!");
        }
    } t;

    Wrapper<Foo> w;
    w.conditional_call(t); // heyy! (if foo didn't exist, then fallback)
}

如果我给 Checker 起别名在类范围内使用using LocalChecker = typename T::template Checker<U>; , 有用;但是,我想了解是否还有其他方法而不使用 using 。另外,我需要template吗?在这个using定义?因为 Clang 和 GCC 对此意见不一。

最佳答案

从 C++17 开始,您不需要 template :: 之间的关键字以及某些上下文中只能命名类型的成员模板特化名称,包括 typename-specifier 语法,该语法在 LocalChecker 中使用别名模板。因此 clang 和 MSVC 在没有 template 的情况下拒绝该行是错误的。 ,并且可能尚未实现此更改。

C++14 [临时名称]/4:

When the name of a member template specialization appears after . or -> in a postfix-expression or after a nested-name-specifier in a qualified-id, and the object expression of the postfix-expression is type-dependent or the nested-name-specifier in the qualified-id refers to a dependent type, but the name is not a member of the current instantiation (14.6.2.1), the member template name must be prefixed by the keyword template. Otherwise the name is assumed to name a non-template.

已替换为 C++17 [temp.names]/4 :

The keyword template is said to appear at the top level in a qualified-id if it appears outside of a template-argument-list or decltype-specifier. In a qualified-id of a declarator-id or in a qualified-id formed by a class-head-name or enum-head-name, the keyword template shall not appear at the top level. In a qualified-id used as the name in a typename-specifier, elaborated-type-specifier, using-declaration, or class-or-decltype, an optional keyword template appearing at the top level is ignored. In these contexts, a < token is always assumed to introduce a template-argument-list. In all other contexts, when naming a template specialization of a member of an unknown specialization ([temp.dep.type]), the member template name shall be prefixed by the keyword template.

由于上述规则只需要关键字 template当成员模板专门化被命名时,而不仅仅是成员模板本身,它看起来很简单 T::Checker ,除了T::template Checker ,应该可以使用 is_detected 来处理示例的部分。 。 (我们不需要 typename ,因为我们命名的是别名模板,而不是该模板的特化类型。)但尚不清楚为什么添加模板会在编译器执行或不执行时产生影响不需要帮助确定含义。开放CWG issue 1478是相关的。

无论如何,编译器似乎确实更喜欢 template提示:你的程序带有 is_detected<T::template Checker, ...在 clang++、g++ 和 msvc 上成功编译: see on godbolt .

关于C++:模板 模板参数的模板成员作为模板类的参数 需要模板 模板参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62055109/

相关文章:

c++ - 为什么 `std::compare_three_way` 不是 `std::strict_weak_order` ?

c++ - 不活动后自动关闭 Adob​​e Reader C++

c++ - 在赋值中转换指针类型

c++ - 函数模板的 typedef(部分实例化)

c++ - clang-11 是否通过 -fcoroutines 标志调用 <coroutine> header ?

c++ - 为什么std::visit in a unsatisfied concept会导致gcc编译错误

c++ - QTextEdit显示的 block 中图像后的文本格式

c++ - 具有相似索引的值的总和

c++ - 插入类作为 STL 映射键值

c++ - 如何提高该模式所需的模板递归深度?