jeudi 31 août 2023

C++ syntax problem when template-ifying a source [duplicate]

When making some code more geeric by turning some classes into class templates, I am getting the following syntax error with C++11 and g++ v11.4:

foo.cpp: In member function ‘const EP<F>::Id* EP<F>::Lex::search(const char*) const’:
foo.cpp:64:29: error: expected primary-expression before ‘,’ token
   64 |         return ids_.search<S, const char*> (name); // ERROR 1 HERE
      |                             ^
foo.cpp:64:31: error: expected primary-expression before ‘const’
   64 |         return ids_.search<S, const char*> (name); // ERROR 1 HERE
      |                               ^~~~~
foo.cpp:64:31: error: expected ‘;’ before ‘const’
foo.cpp:64:42: error: expected unqualified-id before ‘>’ token
   64 |         return ids_.search<S, const char*> (name); // ERROR 1 HERE
      |                                          ^
foo.cpp: In member function ‘EP<F>::Id* EP<F>::Lex::search(const char*)’:
foo.cpp:69:40: error: expected primary-expression before ‘const’
   69 |         return ids_.search<Id::Search, const char*> (name); // ERROR 2 HERE
      |                                        ^~~~~
foo.cpp:69:40: error: expected ‘;’ before ‘const’
foo.cpp:69:51: error: expected unqualified-id before ‘>’ token
   69 |         return ids_.search<Id::Search, const char*> (name); // ERROR 2 HERE
      |                                                   ^

So maybe the < is read as less-than instead of as template argument?

Unfortunately, the error messages don't help with finding the correct syntax. Checking with diff shows no obvious typos.

For reference, here is (a reduced test case of) my take on the templated version of EP and the original version where EP is a plain struct:

EP as class template (syntax error)

#include <cstring>
#include <iostream>
#include <cmath>

template<class X>
struct XTree
{
    typedef X element_type;
    X a_, b_;
    static X nan_;

    template<class S, class V>
    const X* search (V const& val) const
    {
        const S& s = S();
        if (s (a_, val) == 0) return &a_;
        if (s (b_, val) == 0) return &b_;
        return &nan_;
    }

    template<class S, class V>
    X* search (V const& val)
    {
        const S& s = S();
        if (s (a_, val) == 0) return &a_;
        if (s (b_, val) == 0) return &b_;
        return &nan_;
    }
};

template<class F>
struct EP
{
    struct Id;
    struct Lex;
};

template<class F>
struct EP<F>::Id
{
    const char* name_ = "NaN";
    F value_;

    Id (const char* name, F val) : name_(name), value_(val) {}

    struct Search
    {
        int operator () (const Id& i, const char* const& name) const
        {
            return std::strcmp (i.name_, name);
        }
    };
};

template<class F>
struct EP<F>::Lex
{
    typedef XTree<EP<F>::Id> Tree;
    Tree ids_ { { "aa", 11.0 }, { "cc", 22.0 } };

    auto search (const char* name) const -> const typename EP<F>::Id*
    {
        using S = typename Id::Search;
        return ids_.search<S, const char*> (name); // ERROR 1 HERE
    }

    auto search (const char* name) -> typename EP<F>::Id*
    {
        return ids_.search<Id::Search, const char*> (name); // ERROR 2 HERE
    }

    F value (const char *str) const
    {
        const EP<F>::Id *id = search (str);
        return id->value_;
    }
};

template<> EP<double>::Id XTree<EP<double>::Id>::nan_ { "NaN", std::nan("") };


int main()
{
    auto lex = EP<double>::Lex();
    std::cout << lex.value ("aa") << std::endl;
    std::cout << lex.value ("bb") << std::endl;
    std::cout << lex.value ("cc") << std::endl;

    return 0;
}

EP as class (works)

#include <cstring>
#include <iostream>
#include <cmath>

template<class X>
struct XTree
{
    typedef X element_type;
    X a_, b_;
    static X nan_;

    template<class S, class V>
    const X* search (V const& val) const
    {
        const S& s = S();
        if (s (a_, val) == 0) return &a_;
        if (s (b_, val) == 0) return &b_;
        return &nan_;
    }

    template<class S, class V>
    X* search (V const& val)
    {
        const S& s = S();
        if (s (a_, val) == 0) return &a_;
        if (s (b_, val) == 0) return &b_;
        return &nan_;
    }
};


struct EP
{
    struct Id;
    struct Lex;
};


struct EP::Id
{
    const char* name_ = "NaN";
    double value_;

    Id (const char* name, double val) : name_(name), value_(val) {}

    struct Search
    {
        int operator () (const Id& i, const char* const& name) const
        {
            return std::strcmp (i.name_, name);
        }
    };
};


struct EP::Lex
{
    typedef XTree<EP::Id> Tree;
    Tree ids_ { { "aa", 11.0 }, { "cc", 22.0 } };

    auto search (const char* name) const -> const EP::Id*
    {
        using S = typename Id::Search;
        return ids_.search<S, const char*> (name); // fine
    }

    auto search (const char* name) -> EP::Id*
    {
        return ids_.search<Id::Search, const char*> (name); // fine
    }

    double value (const char *str) const
    {
        const EP::Id *id = search (str);
        return id->value_;
    }
};

template<> EP::Id XTree<EP::Id>::nan_ { "NaN", std::nan("") };


int main()
{
    auto lex = EP::Lex();
    std::cout << lex.value ("aa") << std::endl;
    std::cout << lex.value ("bb") << std::endl;
    std::cout << lex.value ("cc") << std::endl;
    return 0;
}

Maybe someone is so kind to show me the correct syntax. FYI, the output of the non-template EP version is:

11
nan
22

Aucun commentaire:

Enregistrer un commentaire