views:

154

answers:

3

Hello,

Question

Following code fails with a error message :

t.cpp: In function `void test()':
t.cpp:35: error: expected primary-expression before '>' token
t.cpp:35: error: expected primary-expression before ')' token

Now I don't see any issues with the code and it compiles with gcc-4.x and MSVC 2005 but not with gcc-3.4 (which is still quite popular on some platforms).

#include <string>
#include <iostream>

struct message {
        message(std::string s) : s_(s) {}
        template<typename CharType>
        std::basic_string<CharType> str()
        {
                return std::basic_string<CharType>(s_.begin(),s_.end());
        }
private:
        std::string s_;
};


inline message translate(std::string const &s)
{
        return message(s);
}


template<typename TheChar>
void test()
{
        std::string s="text";
        std::basic_string<TheChar> t1,t2,t3,t4,t5;

        t1=translate(s).str<TheChar>(); // ok

        char const *tmp=s.c_str();
        t2=translate(tmp).str<TheChar>(); // ok

        t3=message(s.c_str()).str<TheChar>(); // ok

        t4=translate(s.c_str()).str<TheChar>(); // fails

        t5=translate(s.c_str()).template str<TheChar>(); // ok

        std::cout << t1 <<" " << t2 <<" " << t3 << " " << t4 << std::endl;
}

int main()
{
        test<char>();
}

Is it possible to workaround it on the level of translate function and message class, or maybe my code is wrong, if so where?

Edit:

http://stackoverflow.com/questions/2013129/bugs-related-to-template-functions-in-gcc-3-4-6 says I need to use keyword template but should I?

Is this a bug? Do I have to write a template keyword? Because in all other cases I do not have to? And it is quite wired I do not have to write it when I use ".c_str()" member function.

Why gcc-4 not always an option

This program does not starts when compiled with gcc-4 under Cygwin

#include <iostream>
#include <locale>

class bar : public std::locale::facet  {
public:
        bar(size_t refs=0) : std::locale::facet(refs)
        {
        }
        static std::locale::id id;
};

std::locale::id bar::id;


using namespace std;

int main()
{
        std::locale l=std::locale(std::locale(),new bar());
        std::cout << has_facet<bar>(l) << std::endl;
        return 0;
}

And this code does not compiles with gcc-4.3 under OpenSolaris 2009- broken concepts checks...

#include <map>
struct tree {
   std::map<int,tree> left,right;
};
+5  A: 

This is a bug in the old compiler. Newer GCC's, from 4.0 to (the yet unreleased) 4.5, accept it, as they should. It is standard C++. (Intel and Comeau accept it also.)

Regarding cygwin and opensolaris, of course gcc-3.4 is not the only option: the newer versions (the released 4.4.3, or the unreleased 4.5 branch) work fine on these OS'es. For cygwin, it's part of the official distribution (see the gcc4* packages in the list). For opensolaris, you can compile it yourself (and instructions on how to do so can easily be found with Google).

FX
True -- though, for a program distributed to other users, "you'll need to compile a compiler in order to build it" does not appeal so much....
Brooks Moses
Hey, hi Brooks!
FX
See my examples where gcc-4.3 is broken. gcc-4.x is not always an option.
Artyom
+1  A: 

I would try to use a different workaround, since adding the template disambiguator there is incorrect and will break if you move to a different compiler later on.

I don't know the real code, but passing a regular std::string seems to work (option 1: avoid converting to const char * just to create a temporary) or you could provide an overloaded translate that takes a const char* as argument (if the compiler does not complain there), depending on your requirements.

David Rodríguez - dribeas
+3  A: 

As mentioned elsewhere, that seems to be a compiler bug. Fair enough; those exist. Here's what you do about those:

#if defined(__GNUC__) && __GNUC__ < 4
// Use erroneous syntax hack to work around a compiler bug.
t4=translate(s.c_str()).template str<TheChar>();
#else
t4=translate(s.c_str()).str<TheChar>();
#endif

GCC always defines __GNUC__ to the major compiler version number. If you need it, you also get __GNUC_MINOR__ and __GNUC_PATCHLEVEL__ for the y and z of the x.y.z version number.

Brooks Moses