可变参数模板代码中的GCC vs MSVC编译错误

时间:2017-06-27 09:57:59

标签: c++ qt templates

有人可以向我解释为什么gcc会输出这个错误吗?

 /media/projects/src/libs/GUIElements/include/GUIElements/TemplatedFlagManager.h:195:
 error: ‘ClearQueue’ was not declared in this scope
             ClearQueue<QueueType>();
               ^     
/media/projects/src/libs/GUIElements/include/GUIElements/TemplatedFlagManager.h:35: error: 
    ‘typename std::enable_if<(I < sizeof... (Tp)), void>::type for_each(std::tuple<_Args2 ...>&, FuncT) 
    [with long unsigned int I = 1ul; FuncT = FlagNotifier<Args>::AddSubscriber(QSharedPointer<FlagSubscriber>)
    [with Args = {SystemFlags::EAppFlags, SystemFlags::EQueueFlags, SystemFlags::EMessageFlags}]::<lambda(auto:2)>;
    Tp = {QList<SystemFlags::EAppFlags>, QList<SystemFlags::EQueueFlags>, QList<SystemFlags::EMessageFlags>}; 
    typename std::enable_if<(I < sizeof... (Tp)), void>::type = void]’,
    declared using local type ‘FlagNotifier<Args>::AddSubscriber(QSharedPointer<FlagSubscriber>)
    [with Args = {SystemFlags::EAppFlags, SystemFlags::EQueueFlags, SystemFlags::EMessageFlags}]::<lambda(auto:2)>’, 
    is used but never defined [-fpermissive]
    for_each(std::tuple<Tp...>& t, FuncT f)
    ^

在此代码中:

template <typename... Args>
class FlagNotifier
{
....

    void AddSubscriber(QSharedPointer<FlagSubscriber> sub)
    {
        for_each(flagQueues, [&](auto queue){
        using QueueType = typename decltype(queue)::value_type;
        for(auto flag : queue)
        {
            auto& group = std::get<get_index<QueueType, Args...>::value>(flagGroups);
            group[flag].push_back(sub);
        }

        ClearQueue<QueueType>();
        sub->ApplyState();
    });
    }   

    template <typename T>
    void ClearQueue(){
        auto& flagQueue = std::get<get_index<T, Args...>::value>(this->flagQueues);
        flagQueue.clear();
    }
    std::tuple<QList<Args>...> flagQueues;
    std::tuple<QHash<Args, QList<QSharedPointer<FlagSubscriber>>>...> flagGroups;
}

msvc完全没问题。 &#34;自动排队&#34;实际上是元组的成员

std::tuple<QList<Args>...> flagQueues;

因此类型应该易于推理,但这个模糊的警告......

P.S。

for_each取自此问题:stackoverflow.com/a/6894436/1143162

get_index来自:stackoverflow.com/a/18063608/1143162

2 个答案:

答案 0 :(得分:3)

Type a word: hellothere Length of the first part: 3 Result: hel 被视为非依赖名称,而您希望它将其视为依赖名称。

更改为

ClearQueue<QueueType>();

应解决您的问题。

需要额外this->template ClearQueue<QueueType>(); 才能正确解析表达式。

答案 1 :(得分:2)

现在,回答这个问题。 free software已经提到 出错了,我会尝试解释为什么

FlagNotifier是一个模板类。当您调用其成员函数ClearQueue时,在某些情况下,编译器可能不清楚它是应该调用成员函数还是自由函数ClearQueue(假设您有一个)。

让我们来看看这个更简单的玩具示例:

libc*so

这应该编译的原因是我可能已经定义了B类的特化,它没有&#34; foo&#34;功能,例如

#include <iostream>

template<typename T>
struct B {
    int f();
};

template<typename T>
struct D : B<T> {
    int g();
};

template<typename T>
int D<T>::g() {
    return f();  // error: should be ‘this->f()’
}

int main()
{
  return 0;
}

然后以下代码将被破坏:

template<>
struct B<int> {
};

因此,C ++标准要求在这种情况下明确使用 this-&gt;

现在,为什么Visual Studio没有抱怨?因为它不符合有关此规则的标准。原因是这个编译器是在C ++标准中的模板特化规则稳定之前很久才引入的,后来微软不愿意破坏向后兼容性。 在Visual C ++ 2017中,他们引入了一个强制执行此规则的特殊标志/许可,以及许多其他规则,您可以看到详细信息Jarod42

此外,您可以在链接中找到这个玩具示例: