Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Why does this code compile with MSVC, but not in GCC or Clang?

And how to fix the code?

Here is the code:
https://godbolt.org/z/vcP6WKvG5

#include <memory>
#include <utility>

enum class Format {
    Number,
    Text,    
};

template <template <Format> typename Visitor, typename... Args>
void switchByFormat(Format format, Args&&... args) {
    switch(format) {
        case Format::Number: 
            Visitor<Format::Number>::visit(std::forward<Args>(args)...);
            break;
        case Format::Text: 
            Visitor<Format::Text>::visit(std::forward<Args>(args)...);
            break;
    }
}

struct AstNode {};

template <Format format>
struct ANode: public AstNode {};

using AstNodePtr = std::shared_ptr<AstNode>;

template <template <Format> typename AstNodeT, 
          typename... Args>
struct AstNodeFactory {
    template <Format format>
    struct Visitor {
        static void visit(AstNodePtr& result, Args&&... args)
        {
            result = std::make_shared<AstNodeT<format>>(std::forward<Args>(args)...);
        }
    };
};

template <template <Format> typename AstNodeT,              
          typename... Args>
AstNodePtr makeAstNode(Format format, Args&&... args)
{
    AstNodePtr result;
    switchByFormat<typename AstNodeFactory<AstNodeT, Args...>::Visitor>(format,
                                                                result,
                                                                std::forward<Args>(args)...);
    return result;
}

int main() {
    auto textAnode = makeAstNode<ANode>(Format::Text);
}

Clang link: https://godbolt.org/z/9fxWE9j71

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

The error in Clang is:

source>:45:64: error: typename specifier refers to class template member in 'AstNodeFactory<ANode>'; argument deduction not allowed here
    switchByFormat<typename AstNodeFactory<AstNodeT, Args...>::Visitor>(format,

GCC link: https://godbolt.org/z/4EvrzGWYE

GCC error:

In instantiation of 'AstNodePtr makeAstNode(Format, Args&& ...) [with AstNodeT = ANode; Args = {}; AstNodePtr = std::shared_ptr<AstNode>]':
<source>:52:53:   required from here
<source>:45:5: error: 'typename AstNodeFactory<ANode>::Visitor' names 'template<enum class Format format> struct AstNodeFactory<ANode>::Visitor', which is not a type
   45 |     switchByFormat<typename AstNodeFactory<AstNodeT, Args...>::Visitor>(format,
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

>Solution :

Since Visitor is a template class rather than a type, you need to specify the template keyword

switchByFormat<AstNodeFactory<AstNodeT, Args...>::template Visitor>(
                                                //^^^^^^^^
  format, result, std::forward<Args>(args)...);

Demo.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading