c++ - `apply` 模板在 g++ 中编译但在 clang++ 和 vc++ 中不编译

标签 c++ templates variadic-templates template-meta-programming partial-application

以下代码compiles successfullyg++ 7.2.0 中(编译标志为 -std=c++14 -Wall -Wextra -Werror -pedantic-errors),但在 clang++ 5.0.0(具有相同的标志,-std=c++14 -Wall -Wextra -Werror -pedantic-errors)和 vc++ 15.4 (编译标志为 /EHsc/Za/std:c++14/permissive-):

template <template <typename...> class Functor, typename... FixedArguments>
struct apply
{
    template <typename... FreeArguments>
    using type = Functor<FixedArguments..., FreeArguments...>;
};

template <typename, typename>
struct Bar{};

template <template <typename...> class>
struct Foo{};

int main()
{
    (void)Foo<apply<Bar, int, char>::type>{};
}

哪种编译器行为符合标准?这样的模板 apply 怎么也可以更改为在 clang++ 上编译?

clang++ 错误信息:

5 : <source>:5:15: error: too many template arguments for class template 'Bar'
        using type = Functor<FixedArguments..., FreeArguments...>;
                     ^                          ~~~~~~~~~~~~~~~~~
16 : <source>:16:15: note: in instantiation of template class 'apply<Bar, int, char>' requested here
    (void)Foo<apply<Bar, int, char>::type>{};
              ^
9 : <source>:9:8: note: template is declared here
struct Bar{};

vc++ 错误信息:

5 : <source>(5): error C2977: 'Bar': too many template arguments
9 : <source>(9): note: see declaration of 'Bar'
16 : <source>(16): note: see reference to class template instantiation 'apply<Bar,int,char>' being compiled

最佳答案

注意:看了这个之后,如果 Bar 是别名模板而不是类模板,这个答案就是正确的。解决方法有效,但出于其他原因。请参阅构造函数答案以获得 OP 的正确答案。

这个问题被称为“别名缺陷”,我们在实现 kvasir::mpl 时遇到了很多挑战。问题在于 Bar 恰好采用两个参数,但 sizeof...(FixedArguments)+sizeof...(FreeArguments) 加起来可能不等于 2。

编译器可以尝试通过所有别名调用跟踪潜在的元数,并且仅在用户实际传递除 2 之外的其他内容时才发出错误,或者它可以通过证明可能发生错误来“急切地”给出错误。

我发现解决这个问题的有效方法是根据输入的大小进行别名调用 https://godbolt.org/g/PT4uaE

template<bool>
struct depends{
    template<template<typename...> class F, typename...Ts>
    using f = F<Ts...>;
};

template<>
struct depends<false>{
    template<template<typename...> class F, typename...Ts>
    using f = void;
};

template <template <typename...> class Functor, typename... FixedArguments>
struct apply
{
    template <typename... FreeArguments>
    using type = typename depends<(sizeof...(FixedArguments)+sizeof...(FreeArguments) == 2)>::template f<Functor, FixedArguments..., FreeArguments...>;
};

template <typename, typename>
struct Bar{};

template <template <typename...> class>
struct Foo{};

int main()
{
    (void)Foo<apply<Bar, int, char>::type>{};
}

应该注意的是,我测试过的所有编译器都不需要限制为两个,一个可以很容易地限制为 sizeof...(FixedArguments)+sizeof...(FreeArguments) != 100000 并且编译器仍然会接受它,仅当在具体调用中实际无法解决问题时才会发出错误。

我实际上想改进我的心智模型,了解它在内部如何工作,以便提出更快的解决方法,在 kvasir::mpl 中,我们目前正在尝试在幕后手动跟踪元数,以消除依赖确实会减慢速度的调用。

关于c++ - `apply` 模板在 g++ 中编译但在 clang++ 和 vc++ 中不编译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47432221/

相关文章:

c++ - 使用类模板需要模板参数列表链接列表

c++ - 如何将 std::vector 设置为模板的默认参数?

c++ - 可变参数 lambda 捕获的解决方法

C++ 嵌入式模板模板

c++ - 在 Xcode 中编译 C++ 时出现很多错误

Java Play 2 - 模板化

c++ - 非 Mac PC 上的 iPhone c++ 开发/编译器? (Windows?Linux?)

c++ - 将argpack分成两半?

c++ - 错误 LNK2019 : unresolved external symbol (project with snappy library)

c++ - Cuda 中的多个 GPU - 以前可以工作的代码,但现在不行了