13

I'm seeing some odd behaviour when returning a string literal from a function that should perform an implicit conversion with g++ (version 4.7.3). Can anyone explain why the following code:

#include <stdio.h>

class Test
{
public:
  template <unsigned int N>
  Test(const char (&foo)[N])
  {
    printf("Template const char array constructor\n");
  }

  Test(char* foo)
  {
    printf("char* constructor\n");
  }
};

Test fn()
{
  return "foo";
}

int main()
{
  Test t("bar");
  Test u = fn();

  return 0;
}

produces the result:

Template const char array constructor
char* constructor

on g++? The surprising thing being that the char* constructor is chosen in preference to the const char array constructor when generating the return value from fn(). Admittedly there is a warning, "deprecated conversion from string constant to 'char*'"

Even more surprisingly if you remove the char* constructor then the code doesn't compile with g++.

It works as expected with clang (Template constructor used both times), which makes me think this is a compiler bug, but maybe it's just a weird corner of the C++ spec - could anyone confirm?

8
  • Your compiling c++11, arent you? Commented Feb 26, 2014 at 22:31
  • @Paranaix I'm seeing this fail on GCC 4.8 in C++11 mode, so even if the OP isn't, that isn't the problem. Commented Feb 26, 2014 at 22:32
  • String literals aren't special here, except perhaps for the deprecated conversion to char*, it behaves the same way with other arrays too: const char foo[4] = {}; return foo; fails with "error: could not convert ‘(const char*)(& foo)’ from ‘const char*’ to ‘Test’" Commented Feb 26, 2014 at 22:40
  • The same applies to function references: they get converted to pointers, and any constructor that accepts a reference is not usable: struct S { S(S(&)()); }; S f() { return f; } is accepted by clang, but gcc reports "error: could not convert ‘f’ from ‘S (*)()’ to ‘S’" A workaround could be return S(f);, or in your example, return Test("foo"); Commented Feb 26, 2014 at 22:54
  • @gwiazdorrr You mean "if", not "since", surely? Commented Feb 26, 2014 at 23:00

2 Answers 2

6

It appears that this is a bug affecting several versions of gcc which has been reported over and over again, most recently about a month ago against the most recent version, 4.8.2. See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24666

Sign up to request clarification or add additional context in comments.

2 Comments

+1 A workaround is to use an explicit conversion instead of an implicit one, i.e. return Test( "foo" ).
As of today (slightly different but possibly related: gcc.gnu.org/bugzilla/show_bug.cgi?id=16333) this still stands
1

If you want a reusable C++03 workaround (i.e. one in which you won't have to care about what the return type is, as long it is constructible from a char array), you will have to use some kind of a char array wrapper.

template <size_t N>
struct char_array_ref
{
    typedef const char (&ref_type)[N];
    ref_type ref;

    template <typename T>
    operator T() const
    {
        return T(ref);
    }
};

template <size_t N>
char_array_ref<N> stupid_gxx_use_array_reference(const char (&chars)[N])
{
    return char_array_ref<N> { chars };
}


Test fn()
{
  return stupid_gxx_use_array_reference("foo");
}

Should be easy to regex propagate this across your codebase, too.

Obviously, in your code you can change stupid_gxx_use_array_reference into something less verbose.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.