`apply`模板用g ++编译,但不用clang ++和vc ++编译

Con*_*tor 2 c++ templates partial-application template-meta-programming variadic-templates

以下代码在g ++ 7.2.0(编译标志)中成功编译,但无法在clang ++ 5.0.0(具有相同的标志)和vc ++ 15.4(编译标志)中编译:-std=c++14 -Wall -Wextra -Werror -pedantic-errors-std=c++14 -Wall -Wextra -Werror -pedantic-errors/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>{};
}
Run Code Online (Sandbox Code Playgroud)

哪种编译器行为符合标准?如何修改这样的模板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{};
Run Code Online (Sandbox Code Playgroud)

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
Run Code Online (Sandbox Code Playgroud)

odi*_*erd 5

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

这个问题被称为"别名漏洞",我们在kvasir :: mpl的实现中遇到了很多挑战.问题是Bar只需要两个参数,但sizeof...(FixedArguments)+sizeof...(FreeArguments)除了2之外还可以加起来.

编译器可以通过所有别名调用尝试跟踪潜在的arity,并且只在用户实际传递除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>{};
}
Run Code Online (Sandbox Code Playgroud)

应该注意的是,在我测试过的所有编译器上都不需要约束到两个,一个可能就像一个简单的约束一样,sizeof...(FixedArguments)+sizeof...(FreeArguments) != 100000如果事情实际上在一个具体的调用上没有成功,编译器仍然只会发出错误.

我真的希望改进我的心理模型,以便在内部进行更快速的工作,在kvasir :: mpl我们正在尝试在幕后手动跟踪arity以消除依赖调用把事情放慢一点.