【问题标题】:How to fix 'wrong number of template arguments' when C++11 enabled'?启用 C++11 时如何修复“错误数量的模板参数”?
【发布时间】:2018-12-03 09:40:21
【问题描述】:

我有一些使用模板的复杂第三方代码。使用 gcc 7.3.0,如果指定了 gcc 标志 -std=gnu++98,则它可以构建,但否则会给出编译错误(即使用 C++11 编译)。我需要修复 C++11 编译。代码如下(抱歉不完整,头文件比较复杂):

#define CPP11 (__cplusplus > 199711L)

namespace csl
{
namespace PostExec
{

struct Complement
{
    static int64_t Execute(int64_t v)
    {
        return ~v;
    }
};

template<size_t bitWidth, bool maskOutput>
struct Mask
{
    static int64_t Execute(int64_t v)
    {
        return 0;
    }
};

#if CPP11
template<typename P, typename... PS>
struct Compound
{
    template<typename T>
    static T&& Execute(T&& v)
    {
        if (sizeof...(PS) > 0)
        {
            return Compound<PS...>::Execute(P::Execute(std::forward<T>(v)));    <<<< COMPILER ERROR HERE
        }
        return P::Execute(std::forward<T>(v));
    }
};
#else
template<typename P1, typename P2>
struct Compound
{
    static int64_t Execute(int64_t v)
    {
        return P1::Execute(P2::Execute(v));
    }
};
#endif

}
}

using namespace csl;
class CModel
{
public:

    void f1();

private:
    void Execute() { }

    static const size_t PAGE_COUNT = 1;

    static size_t CurrentPage;
    static CPage<1, 0> State[PAGE_COUNT];
};

void CModel::f1()
{
    int64_t n[5];
    StepLogicalNXOr<1, false>::Execute(Page.N[1], n[0], n[1]);
}

size_t CModel::CurrentPage = 0;

CPage <1919, 0> CModel::State[PAGE_COUNT] = {
    CPage <1, 0>()    
};

编译器错误(定义 CPP11 时)为:

<snip>: error: wrong number of template arguments (0, should be at least 1)
  return Compound<PS...>::Execute(P::Execute(std::forward<T>(v)));
         ~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
<snip>: note: provided for ‘template<class P, class ... PS> struct csl::PostExec::Compound’
struct Compound
       ^~~~~~~~

我知道这很复杂,但如果有人能提供帮助,我将不胜感激。

【问题讨论】:

    标签: c++ c++11 templates variadic-templates template-meta-programming


    【解决方案1】:

    您尝试过 SFINAE 吗?

    我的意思是...(注意:代码未测试)

    template<typename T>
    static typename std::enable_if<0 != sizeof...(PS), T&&>::type Execute(T&& v)
    { return Compound<PS...>::Execute(P::Execute(std::forward<T>(v))); }
    
    
    template<typename T>
    static typename std::enable_if<0 == sizeof...(PS), T&&>::type Execute(T&& v)
     { return P::Execute(std::forward<T>(v)); }
    

    我的意思是...您的代码无法运行,因为当 sizeof...(PS) == 0 行时

     return Compound<PS...>::Execute(P::Execute(std::forward<T>(v)));
    

    已编译,Compound 需要一个或多个模板参数;不能接受零模板参数。

    我知道这条线正在测试中

    if (sizeof...(PS) > 0)
    

    但你需要if constexpr

    if constexpr (sizeof...(PS) > 0)
    

    在测试为假时避免编译;但不幸的是,if constexpr 只能从 C++17 开始使用。

    所以我在 C++11 中看到的唯一解决方案是将方法 Execute() 拆分为两个版本,并根据 sizeof...(PS) 的值启用/禁用第一个或第二个。

    【讨论】:

    • 感谢您的回答。我尝试了您建议的代码(您的第一个代码块),但现在 iq = PostExec::Compound<:mask maskoutput>, PostExec::Complement>::Execute(BitwiseOps::XOr::执行(ia, ib));
    • 错误是:错误:重载 'Execute(int64_t)' 的调用不明确 iq = PostExec::Compound<:mask maskoutput>, PostExec::Complement>::Execute (BitwiseOps::XOr::Execute(ia, ib)); ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~
    • @DavidA - 抱歉:对于第二种情况,我在std::enable_if&lt;&gt; 之后忘记了::type;我不知道这是否是问题(老实说,我不这么认为)但我的第一个答案是错误的;答案更正。您可以尝试使用更正后的代码吗?
    • 代码确实会随着该更改进行编译。谢谢。看来,从您对 ritesh 的评论来看,您认为您的解决方案比他的更正确?
    • @DavidA - 是的,因为您发布的代码打算(错误地)递归调用Execute(),使用Ps... 类型;在 ritesh 的解决方案中,模板列表永远不会改变:永远是 P, Ps...;所以代码编译,但(如果我没记错的话)调用自己直到达到递归限制。
    【解决方案2】:
    Compound<PS...>::Execute(P::Execute(std::forward<T>(v)));
    

    上面调用中的P是问题的原因。 复合模板有 2 个参数,这里只传递 1 个。

    我已经在所有给定的约束范围内进行了尝试,我觉得下面的代码应该可以防止编译器错误。

    template<typename P, typename... PS>
    struct Compound
    {
        template<typename T>
        static T&& Execute(T&& v)
        {
            if (sizeof...(PS) > 0)
            {
                return Compound<P,PS...>::Execute(P::Execute(std::forward<T>(v)));   
            }
            return P::Execute(std::forward<T>(v));
        }
    };
    

    希望对你有帮助。

    【讨论】:

    • 防止编译错误但不消耗P, Ps...列表
    • 嗨 Ritesh,感谢您的回答,但似乎 max66 的回答更完整,所以我接受了。
    猜你喜欢
    • 2012-08-14
    • 1970-01-01
    • 1970-01-01
    • 2017-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多