【问题标题】:`apply` template compiles in g++ but not in clang++ and vc++`apply` 模板在 g++ 中编译,但在 clang++ 和 vc++ 中不编译
【发布时间】:2017-11-22 10:24:49
【问题描述】:

g++ 7.2.0 中的以下代码 compiles successfully(编译标志为 -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

【问题讨论】:

  • Clang 给出什么错误?
  • @piwi clang++vc++ 错误消息可在 the link to the godbolt.org in the question 获得。我也将它们添加到问题中。
  • 我的不好在发表评论之前没有看到。
  • [temp.res]/8.3。这是格式错误的 NDR。但请参阅core issue 2067
  • @T.C.感谢您的参考!但是如何修复这样的代码才能编译呢?

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


【解决方案1】:

注意:看了这个之后,如果 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 中,我们目前正在尝试在幕后手动跟踪 arity 以消除依赖确实会减慢速度的调用。

【讨论】:

  • 谢谢。您能否将解决方法代码复制到您的答案中?
【解决方案2】:

由于@T.C.noted in the comments to the question 这样的代码格式错误(不需要诊断)。

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

如果可变参数模板的每个有效特化都需要一个空的 模板参数包,模板格式不正确,无诊断 必填。

C++ 标准的最新草案,“名称解析”部分 [temp.res],第 8.3 段:

...程序格式错误,不需要诊断,如果:

  • ...
  • 可变参数模板的每个有效特化都需要一个空模板参数包...

其他信息:Core Issue 2067

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

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;
};

Live demo

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

【讨论】:

  • 我认为这实际上是正确的答案,而我的解决方案恰好有效。应该注意的是,解决方法会创建一个类型,因此会更慢。
  • @odinthenerd 我已经添加了必要的注释。
  • @odinthenerd 你不介意我接受我的回答而不是你的回答吗?
猜你喜欢
  • 1970-01-01
  • 2018-03-10
  • 2017-01-11
  • 1970-01-01
  • 2011-02-04
  • 1970-01-01
  • 2015-05-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多