variadic模板代码中的GCC VS MSVC编译误差

GCC vs MSVC compilation error in variadic template code

本文关键字:VS MSVC 编译 误差 GCC 代码 variadic      更新时间:2023-10-16

有人可以向我解释为什么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完全可以。"自动队列"实际上是元组的成员

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

因此,该类型应该很容易推论,但这种晦涩的警告...

P.S。

for_each是从这个问题中获取的:stackoverflow.com/a/6894436/1143162

get_index来自以下内容:stackoverflow.com/a/18063608/1143162

ClearQueue<QueueType>();被视为非依赖性名称,而您希望它将其视为依赖。

更改为

this->template ClearQueue<QueueType>();

应该解决您的问题。

正确解析表达式需要额外的template

现在回答问题。JAROD42已经提到了什么是错误的,我会尝试解释为什么

flagnotifier是模板类。当您调用其成员函数Clearqueue时,在某些情况下,编译器可能不清楚它应该是对成员函数或免费函数Clearqueue的调用(假设您有一个(。

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

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

那么以下代码将被打破:

D<int> d;
d.g();

因此,在这种情况下,C 标准需要使用 this-> 明确。

现在,为什么视觉工作室不抱怨?因为它不符合有关此规则的标准。原因是在C 标准中的模板专业规则稳定之前很久就引入了该编译器,后来在Microsoft上不愿破坏向后兼容性。在Visual C 2017中,他们引入了一个特殊的标志/宽容,该标志可以执行此规则,以及许多其他规则,您可以在此处查看详细信息。

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

  • 在Visual Studio 2017中编译
  • 未能在Clang 3.8.0
  • 中编译
  • 未能在GCC 5.4.0中编译