C++ `在g+中应用`模板编译+;但不是叮当作响++;和vc++;

C++ `在g+中应用`模板编译+;但不是叮当作响++;和vc++;,c++,templates,variadic-templates,template-meta-programming,partial-application,C++,Templates,Variadic Templates,Template Meta Programming,Partial Application,g++7.2.0中的以下代码(编译标志为-std=c++14-Wall-Wextra-Werror-pedantic errors)和vc++15.4(编译标志为/EHsc/Za/std:c++14-Wall-Wextra-Werror-pedantic errors)无法在clang++5.0.0中编译(使用相同的标志为-std=c++14-Wall-Wextra-Werror-pedantic errors): vc++错误消息: 5:(5):错误C2977:“Bar”:模板参数太多 9:(

g++7.2.0中的以下代码(编译标志为
-std=c++14-Wall-Wextra-Werror-pedantic errors
)和vc++15.4(编译标志为
/EHsc/Za/std:c++14-Wall-Wextra-Werror-pedantic errors
)无法在clang++5.0.0中编译(使用相同的标志为
-std=c++14-Wall-Wextra-Werror-pedantic errors
):

vc++错误消息:

5:(5):错误C2977:“Bar”:模板参数太多
9:(9):注:见“酒吧”声明
16:(16):注意:请参阅对正在编译的类模板实例化“apply”的引用

注意:看了这篇文章后,如果Bar是别名模板而不是类模板,那么这个答案是正确的。这种变通方法可行,但还有其他原因。有关OP的正确答案,请参见构造器答案

这个问题被称为“别名缺陷”,我们在实现kvasir::mpl时遇到了很多挑战。问题是Bar只接受两个参数,但是除了2之外,
sizeof…(FixedArguments)+sizeof…(FreeArguments)
还可以加起来

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

我发现解决这个问题的有效方法是使别名调用依赖于输入的大小

模板
结构依赖于{
模板
使用f=f;
};
模板
结构依赖于{
模板
使用f=无效;
};
模板
结构应用
{
模板
使用type=typename依赖于::模板f;
};
模板
结构条{};
模板
结构Foo{};
int main()
{
(无效)Foo{};
}
需要注意的是,在我测试过的所有编译器上,并不需要约束为正好两个,一个可以很容易地约束为
sizeof…(FixedArguments)+sizeof…(freeraguments)!=100000
,编译器仍然会接受它,只有在实际调用中出现问题时才会发出错误

实际上,我想改进我的心智模型,了解它如何在内部工作,以便找到更快的解决方法。在kvasir::mpl中,我们目前正在尝试在后台手动跟踪算术,以消除会使事情慢一点的依赖调用。

因为这样的代码格式不正确(无需诊断)

C++14标准,“名称解析”一节[temp.res],第8段:

如果变量模板的每个有效专门化都需要一个空 模板参数包,模板格式错误,无诊断 必需的

< > >强> C++标准的最新草稿,“名称解析”部分[ TEMP.RES ],第8.3段:>P/> …程序格式不正确,无需诊断,如果:

  • 可变模板的每个有效专门化都需要一个空模板参数包
其他信息:

根据标准要求,可以编写此类简单的解决方法:

template <template <typename...> class Functor, typename... Arguments>
struct invoke
{
    using type = Functor<Arguments...>;
};

template <template <typename...> class Functor, typename... FixedArguments>
struct apply
{
    template <typename... FreeArguments>
    using type = typename invoke<Functor, FixedArguments..., FreeArguments...>::type;
};
模板
结构调用
{
使用类型=函子


更新:因为此解决方法使用了一种额外的类型,这会导致程序的编译速度变慢。

Clang会产生什么错误?@piwi-Clang++和vc++错误消息可在上找到。我也将它们添加到了问题中。我的朋友在发布评论之前没有看到它。这是格式错误的NDR。但是请参阅。@T.C.谢谢你u供您参考!但是如何修复这些代码以进行编译呢?谢谢。您能将您的变通代码复制到您的答案中吗?我认为这实际上是正确的答案,我的解决方案正好有效。应该注意的是,变通方法创建了一个类型,因此速度会慢一些。@odinthenerd我已经添加了必要的注释。@odiN先生,你不介意我接受我的答案而不是你的吗?
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{};
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
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>{};
}
template <template <typename...> class Functor, typename... Arguments>
struct invoke
{
    using type = Functor<Arguments...>;
};

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