передача в функцию вызова функции в качестве аргумента без временного переменного

Этот код работает:

    Nmsp::Base* pBase = new Nmsp::Derived;
    *pBase = Nmsp::Derived{}.SetName("New Name");
    nmsp.Operate( *pBase );

Но нужно вызвать функцию таким образом:

    nmsp.Operate( Nmsp::Derived{}.SetName( "New Name") );

В Visual Studio такой код компилируется, но ведет себя не очень (UB), хотя никаких ошибок не выдает. В wandbox при определенных настройках получаю "pure virtual method called" Понятно, что здесь и есть ошибка (которая в VS "скрыто"), но как исправить - не знаю.

При использовании умных указателей уже и VS жалуется на "создание абстрактного объекта".

Весь код привожу ниже:

#include <iostream>

namespace Nmsp
{
    class Base
    {
    public:
        virtual Base& SetName(const std::string& c) = 0;
        virtual ~Base() = default;
        virtual void Func(std::ostream& out) const = 0;

        double param = 1;
    };

    class Derived : public Base
    {
    public:
        Derived()
        {
            std::cout << "Derived Ctor" << ", name=" << name << std::endl;
        }

        Base& SetName(const std::string& c) override
        {
            name = c;
            param = 2;
            std::cout << "SetName" << ", New name=" << name << std::endl;
            std::cout << "SetName" << ", New param=" << param << std::endl;

            return *this;
        }
        void Func(std::ostream& out) const override
        {
            out << "Derived param = " << param << std::endl;
            out << "Derived caption = " << name << std::endl;
        }
        ~Derived()
        {
            std::cout << "Derived Dtor" << ", name=" << name << std::endl;
        }
        std::string name = "Default Name";
    };

    class Holder //: public Base
    {
    public:
        ~Holder()
        {
            if (basePtr)
                delete basePtr;
        }
        template <typename T>
        void Operate(T& bPtr)
        {
            basePtr = &bPtr;
            //basePtr = std::make_unique<T>(std::move(bPtr));
        }

        void Go(std::ostream& out)
        {
            basePtr->Func(out);
        }
    private:
        Base* basePtr = nullptr;
        // std::unique_ptr<Base> basePtr;
    };
}

int main()
{
    Nmsp::Holder nmsp;

    Nmsp::Base* pBase = new Nmsp::Derived;
    *pBase = Nmsp::Derived{}.SetName("New Name");
    nmsp.Operate( *pBase );

    std::cout << "before go" << std::endl;

    // Need to call the function Operate() in this way
    //nmsp.Operate( Nmsp::Derived{}.SetName( "New Name") );

    nmsp.Go( std::cout );

    return 0;
}

Ответы (2 шт):

Автор решения: AlexGlebe

Так вроде пашет :

nmsp.Operate( (new Nmsp::Derived{})->SetName( "New Name") );

Второй подход :

Чтобы принимал только временный аргумент, пишу move-конструктор. Функцию принимающую временный объект. И получается так :

Derived(Derived && d):name(std::move(d.name))
    {
    }

void Operate(Nmsp::Derived && bPtr)
    {
        basePtr = new Nmsp::Derived{std::move(bPtr)};
    }

nmsp.Operate(
  static_cast<Nmsp::Derived && >(
    Nmsp::Derived{}.SetName( "New Name")));

То есть вручную указываю, что объект временный.

Третий подход :

Функция Operate будет всегда создавать новый объект. Пишем виртуальный конструктор копирования.

class Base {
  virtual Base & Copy ( ) const = 0 ;
} ;
class Derived {
  virtual Base & Copy ( ) const {
      return * new Derived (*this);
    }
  Derived(Derived const & d):name(d.name)
    {
    }
} ;
class Holder {
  template <typename T>
    void Operate(T const & bPtr)
    {
        basePtr = & bPtr.Copy ( ) ;
    }
};

И уже точно как вы хотели :

nmsp.Operate(Nmsp::Derived{}.SetName( "New Name"));
→ Ссылка
Автор решения: user7860670

Достаточно перестать смешивать RAII и сырые указатели:

#include <iostream>
#include <string>
#include <memory>
#include <utility>

namespace Nmsp
{
    class Holder //: public Base
    {
    public:
        ~Holder()
        {
        }

        void Operate(::std::unique_ptr<Base> p_base)
        {
            basePtr = std::move(p_base);
        }

        void Go(std::ostream& out)
        {
            basePtr->Func(out);
        }
    private:
        ::std::unique_ptr<Base> basePtr;
    };
}

int main()
{
    Nmsp::Holder nmsp;
    auto p_derived{::std::make_unique<Nmsp::Derived>()};
    p_derived->SetName("New Name");
    nmsp.Operate(::std::unique_ptr<Nmsp::Base>{::std::move(p_derived)});
    std::cout << "before go" << std::endl;
    nmsp.Go( std::cout );
    return 0;
}

https://godbolt.org/z/W58dad

→ Ссылка