views:

184

answers:

2

I'm using gcc 4.3.2.

I have the following code (simplified):

#include <cstdlib>

template<int SIZE>
class Buffer
{
public:
    explicit Buffer(const char *p = NULL) {}
    explicit Buffer(const Buffer &other);

    const char *c_str() const { return m_buffer; }

private:
    char m_buffer[SIZE];
};

typedef Buffer<10> A;
typedef Buffer<20> B;

void Foo(A a) {
}

int main()
{
    B b;
    Foo(b.c_str());  // line 25 fails compilation
    return 1;
}

Compilation yields:

test.cpp: In function ‘int main()’:
test.cpp:25: error: conversion from ‘const char*’ to non-scalar type ‘A’ requested

But there's c-tor receiving const char *.

UDP:

If I remove explicit from 1st c-tor I receive

test.cpp: In function ‘int main()’:
test.cpp:25: error: no matching function for call to ‘Buffer<10>::Buffer(A)’
test.cpp:7: note: candidates are: Buffer<SIZE>::Buffer(const char*) [with int SIZE = 10]
test.cpp:25: error:   initializing argument 1 of ‘void Foo(A)’

If I use Foo(A(b.c_str())) I receive:

test.cpp: In function ‘int main()’:
test.cpp:25: error: no matching function for call to ‘Buffer<10>::Buffer(A)’
test.cpp:25: error:   initializing argument 1 of ‘void Foo(A)’
+13  A: 

Your conversion constructor is declared explicit. Keyword explicit is specifically intended to prevent implicit conversions by that constructor. And an implicit conversion is exactly what you expect to happen in your code (at the Foo call).

Why did you declare your constructor explicit, if you want it to work in implicit conversions?

AndreyT
When B is called A type should be constructed from b.c_str(), which is const char *. A's 1st c-tor receives const char *, so explicit should not be a problem here. Do I miss something?
dimba
Yes. `explicit` means the compiler *will not* do exactly that. If you remove explicit, it will be able to *implicitly* do the conversion.
GMan
@idimba: You are passing a `const char*` to a function that expects `A`. `const char*` is not `A`, so a conversion is required. But the compiler cannot use `A::A(const char *)` conversion constructor, because it is declared `explicit`. If you want this constructor to be used, you have to spell out an explicit conversion `Foo(A(b.c_str()))`
AndreyT
@idimba, Wait - the buffer also has an explicit size. Not sure about null termination anymore now. Sure you didn't want to say `Foo(A(b.c_str()));` ? If you make it implicit, you would also succeed with `Foo("bar");` which seems all wrong.
Johannes Schaub - litb
As you see from UDP Foo(A(b.c_str())) doesn't help ...:(
dimba
I'm afraid that it doesn't help because your copy-constructor is also declared `explicit`, so all your attempts to pass `A` by value will fail. Stop abusing `explicit` :)
AndreyT
I looked up into the Standard again and caught GCC doing the wrong thing (comeau compiles his code with only the first one being implicit) when only the first is implicit: `Foo(b.c_str());` should work fine, but `Foo(A(b.c_str()));` should fail according to the Standard. But GCC fails for both. This is counterintuitive, though, i think. Anyway, make those explicits go away xD
Johannes Schaub - litb
+3  A: 

A and B are totally different types. As Andrey pointed out, there is no implicit callable constructor for conversion. You'll have to write

Foo(A(b.c_str()));

This will create a temporary 'automatic' (unnamed) object of type A using the explicit constructor for const char. And this will be passed to Foo.

RED SOFT ADAIR
Or remove `explicit`, I would add.
GMan