conversion from '...' to non-scalar type '...' requested

Discussion in 'C++' started by tthunder@gmx.de, Jun 5, 2006.

  1. Guest

    Hi @all,

    My small example does not compile... I know, that this (as always) has
    reasons, but I want to know WHY?

    BTW:
    I only get errors with g++ (4.x), BCB (6.0),...
    VS C++ (2005) works perfectly (without warnings etc.)

    class classValue
    {
    public:
    classValue() {}
    };

    class classHolder
    {
    public: classHolder(classValue &ami) {} // <== I know, but in
    this case reference MUST be non-const
    };

    classHolder getAHolder()
    {
    return classValue(); // <--- Error: conversion from
    'classValue' to non-scalar type 'classHolder' requested
    }


    Using a little trick, everthing works well...

    class classValue
    {
    public:
    classValue() {}
    classValue &self() { return *this; }
    };

    class classHolder
    {
    public: classHolder(classValue &ami) {}
    };

    classHolder getAHolder()
    { return classValue().self();}

    But why must I use this nasty indirection?
    How is this phenomenon called?
    Any other suggestions?

    THX,
    Kirsten
     
    , Jun 5, 2006
    #1
    1. Advertising

  2. wrote:
    > My small example does not compile... I know, that this (as always) has
    > reasons, but I want to know WHY?


    Because it's prohibited by the Standard.

    > BTW:
    > I only get errors with g++ (4.x), BCB (6.0),...
    > VS C++ (2005) works perfectly (without warnings etc.)


    Make sure you disable "language extensions" when compiling with VC++.

    > class classValue
    > {
    > public:
    > classValue() {}
    > };
    >
    > class classHolder
    > {
    > public: classHolder(classValue &ami) {} // <== I know, but in
    > this case reference MUST be non-const
    > };
    >
    > classHolder getAHolder()
    > {
    > return classValue(); // <--- Error: conversion from
    > 'classValue' to non-scalar type 'classHolder' requested


    That's correct. A temporary cannot be bound to a non-const reference.

    > }
    >
    >
    > Using a little trick, everthing works well...
    >
    > class classValue
    > {
    > public:
    > classValue() {}
    > classValue &self() { return *this; }
    > };
    >
    > class classHolder
    > {
    > public: classHolder(classValue &ami) {}
    > };
    >
    > classHolder getAHolder()
    > { return classValue().self();}
    >
    > But why must I use this nasty indirection?


    It's a very bad idea to actually use it.

    > How is this phenomenon called?


    Which one? Playing dirty tricks?

    > Any other suggestions?


    Redesign.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 5, 2006
    #2
    1. Advertising

  3. mlimber Guest

    wrote:
    > Hi @all,
    >
    > My small example does not compile... I know, that this (as always) has
    > reasons, but I want to know WHY?
    >
    > BTW:
    > I only get errors with g++ (4.x), BCB (6.0),...
    > VS C++ (2005) works perfectly (without warnings etc.)


    VS *builds* perfectly. I doubt it would actually work in practice
    except by pure chance.

    >
    > class classValue
    > {
    > public:
    > classValue() {}
    > };
    >
    > class classHolder
    > {
    > public: classHolder(classValue &ami) {} // <== I know, but in
    > this case reference MUST be non-const
    > };
    >
    > classHolder getAHolder()
    > {
    > return classValue(); // <--- Error: conversion from
    > 'classValue' to non-scalar type 'classHolder' requested
    > }


    You are returning type classHolder, so the return value you specify (a
    *temporary* of type classValue) must be converted to a classHolder via
    the constructor you supply. However, according to the C++ Standard,
    non-const references cannot bind to temporaries, and that is a good
    thing and for your protection.

    > Using a little trick, everthing works well...
    >
    > class classValue
    > {
    > public:
    > classValue() {}
    > classValue &self() { return *this; }
    > };
    >
    > class classHolder
    > {
    > public: classHolder(classValue &ami) {}
    > };
    >
    > classHolder getAHolder()
    > { return classValue().self();}
    >
    > But why must I use this nasty indirection?
    > How is this phenomenon called?
    > Any other suggestions?


    You are fighting against the rules of the language here, and this
    trickery won't actually get you anywhere since you'll likely end up
    with a dangling reference in your real code. Either don't use a
    temporary or don't pass a non-const reference to
    classHolder::classHolder() -- that is, either make a copy of the
    classValue object or pass a const reference to it.

    Cheers! --M
     
    mlimber, Jun 5, 2006
    #3
  4. wrote:
    > Hi @all,
    >
    > My small example does not compile... I know, that this (as always) has
    > reasons, but I want to know WHY?


    Because you cannot bound an rvalue to a non-const reference.

    > BTW:
    > I only get errors with g++ (4.x), BCB (6.0),...
    > VS C++ (2005) works perfectly (without warnings etc.)
    >
    > class classValue
    > {
    > public:
    > classValue() {}
    > };
    >
    > class classHolder
    > {
    > public: classHolder(classValue &ami) {} // <== I know, but in
    > this case reference MUST be non-const
    > };
    >
    > classHolder getAHolder()
    > {
    > return classValue(); // <--- Error: conversion from
    > 'classValue' to non-scalar type 'classHolder' requested


    If you could do that, you'd get several more important problems:

    void f(int& i)
    {
    i = 2;
    }

    int main()
    {
    int i = 4;
    double d = 1.0;

    f(i); // ok
    f(d); // ok??
    f(4); // ouch!

    // what should this output?
    std::cout << d;
    }

    For the second call to f(), the double gets converted to a temporary
    int (an rvalue), which gets modified in f(). Do you expect 'd' to get
    modified also? It won't and that's misleading, dangerous and illegal.

    > }
    >
    > Using a little trick, everthing works well...


    Yes, you may do that.

    > class classValue
    > {
    > public:
    > classValue() {}
    > classValue &self() { return *this; }
    > };
    >
    > class classHolder
    > {
    > public: classHolder(classValue &ami) {}
    > };
    >
    > classHolder getAHolder()
    > { return classValue().self();}
    >
    > But why must I use this nasty indirection?


    Because that's how the language is defined. Note that you may also do

    classholder getAHolder()
    {
    classValue v;
    return classHolder(v);
    }


    Jonathan
     
    Jonathan Mcdougall, Jun 5, 2006
    #4
  5. Guest

    Yes, hate me... I believe your explanations, of course!!!!
    But sometimes you NEED to be nasty.

    I explain why I cannot use const...

    class classHolder
    {
    public: classHolder(classValue &ami) {}
    };

    class classHolder_const : public classHolder
    {
    public: classHolder(const classValue &ami) {}
    };

    classValue aValue;
    const classValue aConstValue;
    classHolder aHolder1 = aValue; // <= ok
    classHolder aHolder2 = aConstValue; // <= forbidden
    classHolder_const aHolder3 = aValue; // <= ok
    classHolder_const aHolder4 = aConstValue; // <= ok

    My classHolder may NOT get any const variables.
     
    , Jun 5, 2006
    #5
  6. wrote:
    > Yes, hate me... I believe your explanations, of course!!!!
    > But sometimes you NEED to be nasty.


    When getting personal, like you are doing here, you need to include
    at least the name of whom you reply to. Otherwise the entire forum
    thinks you're calling them nasty (did you know that plural and singular
    form for the second person in English are both "you"?)

    I don't mind being called nasty myself, I don't don't like to fall
    under a blanket occusation.

    > I explain why I cannot use const...
    >
    > class classHolder
    > {
    > public: classHolder(classValue &ami) {}
    > };
    >
    > class classHolder_const : public classHolder
    > {
    > public: classHolder(const classValue &ami) {}
    > };
    >
    > classValue aValue;
    > const classValue aConstValue;
    > classHolder aHolder1 = aValue; // <= ok
    > classHolder aHolder2 = aConstValue; // <= forbidden
    > classHolder_const aHolder3 = aValue; // <= ok
    > classHolder_const aHolder4 = aConstValue; // <= ok
    >
    > My classHolder may NOT get any const variables.


    That's all fine and dandy. But if you're stuck with a certain
    format of your constructors, then you have to be careful with the
    return statements. You simply cannot use 'classValue()' syntax
    where an instance of 'classHolder' is expected. That's all.
    If you need to allow default-initialisation of 'classHolder',
    just give it a default constructor. Otherwise, rethink what your
    classes do and/or how they do it.

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 5, 2006
    #6
  7. mlimber Guest

    wrote:
    > Yes, hate me...


    Don't be so hard on yourself. You've done nothing worthy of such scorn
    and derision... yet (you don't put your open brace on the same line as
    the for statement, do you?).

    > But sometimes you NEED to be nasty.


    But if you do need to be nasty, you had better know what the
    implications of your nastiness are. It appears to me that you don't.

    > I explain why I cannot use const...
    >
    > class classHolder
    > {
    > public: classHolder(classValue &ami) {}
    > };
    >
    > class classHolder_const : public classHolder
    > {
    > public: classHolder(const classValue &ami) {}
    > };
    >
    > classValue aValue;
    > const classValue aConstValue;
    > classHolder aHolder1 = aValue; // <= ok
    > classHolder aHolder2 = aConstValue; // <= forbidden
    > classHolder_const aHolder3 = aValue; // <= ok
    > classHolder_const aHolder4 = aConstValue; // <= ok
    >
    > My classHolder may NOT get any const variables.


    That doesn't really explain much of anything. How are you using that
    non-const reference? That's the real question here since fighting
    against the rules of the language like this will likely bite you in the
    end when you find you have a dangling reference. To reiterate: either
    don't use a temporary or don't pass a non-const reference to
    classHolder::classHolder() -- that is, either make a copy of the
    classValue object or pass a const reference to it.

    Cheers! --M
     
    mlimber, Jun 5, 2006
    #7
  8. Guest

    H

    Victor Bazarov schrieb:

    > wrote:
    > > Yes, hate me... I believe your explanations, of course!!!!
    > > But sometimes you NEED to be nasty.

    >
    > When getting personal, like you are doing here, you need to include
    > at least the name of whom you reply to. Otherwise the entire forum
    > thinks you're calling them nasty (did you know that plural and singular
    > form for the second person in English are both "you"?)


    I am really sorry!!! Big misunderstanding.
    First, it was not meant personal.
    Second, it was generally spoken (doing nasty C++ tricks)

    And "hate me" was meant funny... because when asking question you
    always get the answer: not standard => redesign
    I often do things, which are not the "standard" way. Yes, I fight
    against the language! But only for creating a framework, which can be
    used the "standard" way.
    BTW... Many design patterns use a way which is not the "standard" way.

    > That's all fine and dandy. But if you're stuck with a certain
    > format of your constructors, then you have to be careful with the
    > return statements. You simply cannot use 'classValue()' syntax
    > where an instance of 'classHolder' is expected. That's all.
    > If you need to allow default-initialisation of 'classHolder',
    > just give it a default constructor. Otherwise, rethink what your
    > classes do and/or how they do it.


    classHolder getAHolder()
    { return classHolder (classValue());}

    This compiles...
    Is this ok?
    Nasty trick again?
    Why can't the compiler DO this itself? No you must throw an error...
     
    , Jun 5, 2006
    #8
  9. Guest

    > > I explain why I cannot use const...
    > >
    > > class classHolder
    > > {
    > > public: classHolder(classValue &ami) {}
    > > };
    > >
    > > class classHolder_const : public classHolder
    > > {
    > > public: classHolder(const classValue &ami) {}
    > > };
    > >
    > > classValue aValue;
    > > const classValue aConstValue;
    > > classHolder aHolder1 = aValue; // <= ok
    > > classHolder aHolder2 = aConstValue; // <= forbidden
    > > classHolder_const aHolder3 = aValue; // <= ok
    > > classHolder_const aHolder4 = aConstValue; // <= ok
    > >
    > > My classHolder may NOT get any const variables.

    >
    > That doesn't really explain much of anything. How are you using that
    > non-const reference? That's the real question here since fighting
    > against the rules of the language like this will likely bite you in the
    > end when you find you have a dangling reference. To reiterate: either
    > don't use a temporary or don't pass a non-const reference to
    > classHolder::classHolder() -- that is, either make a copy of the
    > classValue object or pass a const reference to it.


    It just explained, why I cannot use const references...
    But to answer your question... in my "real code" (I constructed this..
    names and everthing) the constructors are all "copy constructors". So I
    copy all values without modifying anything or use references later.

    Yes, therefore I could use const references, but I want to forbid the
    usage of "const instances" with classHolder, but not with
    classHolder_const...
     
    , Jun 5, 2006
    #9
  10. mlimber Guest

    wrote:
    > > That doesn't really explain much of anything. How are you using that
    > > non-const reference? That's the real question here since fighting
    > > against the rules of the language like this will likely bite you in the
    > > end when you find you have a dangling reference. To reiterate: either
    > > don't use a temporary or don't pass a non-const reference to
    > > classHolder::classHolder() -- that is, either make a copy of the
    > > classValue object or pass a const reference to it.

    >
    > It just explained, why I cannot use const references...
    > But to answer your question... in my "real code" (I constructed this..
    > names and everthing) the constructors are all "copy constructors". So I
    > copy all values without modifying anything or use references later.
    >
    > Yes, therefore I could use const references, but I want to forbid the
    > usage of "const instances" with classHolder, but not with
    > classHolder_const...


    Finally we get down to it. Tell us more (and show us more code) about
    why and how you want to do this, and then perhaps we can tell you the
    best way to accomplish what you want to do.

    Cheers! --M
     
    mlimber, Jun 5, 2006
    #10
  11. wrote:
    > [...]
    > classHolder getAHolder()
    > { return classHolder (classValue());}
    >
    > This compiles...


    It does???

    > Is this ok?


    No, certainly not.

    > Nasty trick again?


    Or a compiler bug... Or operator error...

    > Why can't the compiler DO this itself? No you must throw an error...


    Are you sure you're using the right compiler?

    ----------------------------
    struct A {};
    struct B { B(A&) {} };
    B foo() {
    return B(A());
    }
    ----------------------------
    Thank you for testing your code with Comeau C/C++!
    Tell others about http://www.comeaucomputing.com/tryitout !

    Your Comeau C/C++ test results are as follows:

    Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for ONLINE_EVALUATION_BETA1
    Copyright 1988-2003 Comeau Computing. All rights reserved.
    MODE:strict errors C++

    "ComeauTest.c", line 4: error: no instance of constructor "B::B" matches the
    argument list
    The argument types that you used are: (A)
    return B(A());
    ^

    1 error detected in the compilation of "ComeauTest.c".

    In strict mode, with -tused, Compile failed
    Hit the Back Button to review your code and compile options.
    ----------------------------

    V
    --
    Please remove capital 'A's when replying by e-mail
    I do not respond to top-posted replies, please don't ask
     
    Victor Bazarov, Jun 5, 2006
    #11
  12. Guest

    mlimber schrieb:

    >
    > Finally we get down to it. Tell us more (and show us more code) about
    > why and how you want to do this, and then perhaps we can tell you the
    > best way to accomplish what you want to do.
    >
    > Cheers! --M


    I can only tell you more... copying code would not be possible...

    think about two classes

    template<typename T>
    property<T>

    template<typename T>
    property_link<T> : public property_link_any

    -----

    property<T> contains values, and property_link<T> is only a "link" to a
    property<T> (contains a pointer, of course).
    BTW: property_link_any can link to ANY property<T>. Of course in the
    real code, there are lots of compatibility checks...

    Now I am linking...

    property<T> myProp
    const property_link<T> myLink = myProp;

    ok!

    using a constant version of property_link<T> I can only use
    const-member-functions of property<T>. Perfect! But I can do nasty
    things now...

    property_link<OtherT> myOtherLink = myLink;

    A kind of copy constructor is called, and myOtherLink links to the same
    thing as myLink... Now imagine you COULD (just imagine... makes my
    explanation easier) access T via OtherT => nothing is const now!

    Therefore:
    property_link<T>::property_link(property_link_any &) <= does not allow
    the example
    const_property_link<T>::const_property_link(const property_link_any &)
    <= I want to force the usage of this class instead.

    In my short example I have not mentioned the default constructor and
    detailed stuff... but forget this for one moment, please... I have
    managed those details already.
     
    , Jun 5, 2006
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. venu reddy

    conversion to non-scalar type requested error

    venu reddy, Feb 19, 2007, in forum: C Programming
    Replies:
    2
    Views:
    16,984
    Barry Schwarz
    Mar 4, 2007
  2. AddisLig
    Replies:
    0
    Views:
    331
    AddisLig
    Nov 16, 2008
  3. kmw
    Replies:
    5
    Views:
    1,908
    James Kanze
    Oct 29, 2009
  4. Clint Olsen
    Replies:
    6
    Views:
    406
    Jeff 'japhy' Pinyan
    Nov 13, 2003
  5. Mark

    Replace scalar in another scalar

    Mark, Jan 27, 2005, in forum: Perl Misc
    Replies:
    4
    Views:
    193
    Arndt Jonasson
    Jan 27, 2005
Loading...

Share This Page