【问题标题】:Wrong pack expanded in variadic template在可变参数模板中扩展了错误的包
【发布时间】:2017-11-05 05:08:32
【问题描述】:

可变参数模板有一个非常奇怪的问题。似乎扩展了错误的包。这是一个代码sn-p:

#include <tuple>

template<typename...>
struct types {};

template<typename = types<>>
struct Base;

template<typename... Args1>
struct Base<types<Args1...>> {
    template<typename... Args2>
    static auto construct(Args1... args1, Args2&&... args2)
        -> decltype(std::make_tuple(args1.forward()..., std::declval<Args2>()...))
    {
        return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...);
    }
};

struct Derived : Base<> {};

int main() {
    auto test = &Derived::construct<char const(&)[7]>;
}

我收到此错误:

13 : <source>:13:43: error: request for member 'forward' in 'args2#0', which is of non-class type 'const char [7]'
         -> decltype(std::make_tuple(args1.forward()..., std::declval<Args2>()...))
                                     ~~~~~~^~~~~~~
13 : <source>:13:43: error: request for member 'forward' in 'args2#0', which is of non-class type 'const char [7]'
<source>: In function 'int main()':
22 : <source>:22:27: error: unable to deduce 'auto' from '& construct<const char (&)[7]>'
     auto test = &Derived::construct<char const(&)[7]>;
                           ^~~~~~~~~~~~~~~~~~~~~~~~~~~
22 : <source>:22:27: note:   could not resolve address from overloaded function '& construct<const char (&)[7]>'
Compiler exited with result code 1

但是,当包中有值时,它不会发生:

struct HasForward { int forward() { return 0; } };

struct Derived : Base<types<HasForward>> {};

这是 First snippet liveSecond snippet live

这段代码有什么问题?这是编译器错误吗?有什么办法可以克服它并让第一包空着吗?

【问题讨论】:

  • 我的clang++编译没有问题;我想这是一个 g++ 错误。

标签: c++ c++11 variadic-templates


【解决方案1】:

这是编译器错误吗?有什么办法可以克服它并让第一包空着吗?

这看起来像是您的编译器中的一个错误。
要解决这个问题,您可以使用如下示例中的函数声明(无需定义)并使用它来测试您的参数:

template<typename... Args1>
class Base<types<Args1...>> {
    template<typename... T, typename... U>
    static auto ret(types<T...>, types<U...>)
    -> decltype(std::make_tuple(std::declval<T>().forward()..., std::declval<U>()...));

public:
    template<typename... Args2>
    static auto construct(Args1... args1, Args2&&... args2)
    -> decltype(ret(types<Args1...>{}, types<Args2...>{}))
    {
        return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...);
    }
};

有点难看,但是it works 当你的第一个包是空的(根据要求也在 C++11 中)并且所有内容都应该被链接器丢弃。

--- 编辑

正如@W.F. 所建议的那样。在 cmets 中(感谢您的建议,我没有注意到),更容易做到这一点。
只需按如下方式定义您的函数:

static auto construct(Args1... args1, Args2&&... args2)
    -> decltype(std::make_tuple(std::declval<Args1>().forward()..., std::declval<Args2>()...))
{
    return std::make_tuple(args1.forward()..., std::forward<Args2>(args2)...);
}

【讨论】:

  • 也可能更简单:std::declval&lt;Args1&gt;().forward()... 似乎有效。试图进行心智实验以使 OP 代码格式错误,但也失败了 :)
  • @W.F.好点子。我没注意到。我可以使用您的建议来整合答案吗?
猜你喜欢
  • 2014-10-30
  • 1970-01-01
  • 2015-05-21
  • 1970-01-01
  • 2014-04-12
  • 1970-01-01
  • 2014-04-29
相关资源
最近更新 更多