Forum Replies Created

Viewing 15 posts - 121 through 135 (of 349 total)
  • Author
    Posts
  • in reply to: Mixin #628711
    RainerRainer
    Keymaster
        Up
        1
        Down
        ::

        The idea of the Decorator is to dynamically extends an object with responsibilities.

        Have a look at your slightly modified example on godbolt:

        #include <string>
        #include <iostream>
        
        template<typename Printable>
        struct RepeatPrint : Printable
        {
            explicit RepeatPrint(Printable const& printable) : Printable(printable) {}
            void repeat(unsigned int n) const
            {
                while (n-- > 0)
                {
                    this->print();
                }
            }
        };
        
        struct Person
        {
            std::string first;
            std::string last;
            void print() const
            {
                std::cout << first << "," << last << "\n";
            }
        };
        
        int main()
        {
            Person p{"Diana", "O"};
            RepeatPrint<Person> myRepeat(p);
            myRepeat.repeat(4);
            std::cout << "---\n";
            myRepeat.print();
        }
        

        The class RepeatPrint extends the interface of Person.

        Person support the print call, but RepeatPrint supports the print and the repeat call.

        This  means that RepeatPrint extends the interface of Print. This extensions is not dynamically but statically (compile time).

        print is a so-called non-dependent name because its name does not depend on the template parameter T. Non-dependent names are looked up and bound at the point of the template definition. At the point of the template definition there is no print function available. You can overcome this issue in three ways:

        • Make the name dependent: this->print()
        • Introduce the name into the current scope: using Printable::print
        • Call the name fully qualified: Printable::print()

        This post gives you more information: Surprise Included: Inheritance and Member Functions of Class Templates

         

         

         

         

        in reply to: std::tie vs. std::make_pair #628697
        RainerRainer
        Keymaster
            Up
            0
            Down
            ::

            To make your question more genernal:

            std::tie creates lvalue referenes.

            std::tuple creates a std::tuple (std::pair creates a std::pair. A std::pair is a two elements tuple).

            std::tie is often used as a convenience function to unpack values. I use std::pair, std::tuple, and std::tie in the following example.

            #include <functional>
            #include <iostream>
            #include <tuple>
            
            
            std::tuple<int, double, char> returnTuple() {
                return std::make_tuple(2000, 10.5, 'a');
            }
            
            int main(){
            
              // make a tuple
              auto tup1= std::make_tuple(1, 2, 3);
            
              // print the values
              std::cout << "std::tuple tup1: ("<< std::get<0>(tup1) << ", " << std::get<1>(tup1) << ", " << std::get<2>(tup1) << ")" << '\n';
            
              std::cout << '\n';
            
              int first = 1;
              int second = 2;
              int third = 3;
              int fourth = 4;
            
              // create a tuple with references
              auto tup2= std::make_tuple(std::cref(first), std::ref(second), std::ref(third), fourth);
            
              // print the values
              std::cout << "std::tuple tup2: (" << std::get<0>(tup2) << ", " << std::get<1>(tup2) << ", " << std::get<2>(tup2) << ", " << std::get<3>(tup2) << ")" <<  '\n';
            
              std::cout << '\n';
            
              //change the values
              // std::get<0>(tup2)= 1001; ERROR because of std::cref(first)
              first = 1001;
              std::get<1>(tup2) = 1002;
              third = 1003;
              fourth = 1004;
            
              // print the values
              std::cout << "std::tuple tup2: (" << std::get<0>(tup2) << ", " << std::get<1>(tup2) << ", " << std::get<2>(tup2) << ", " << std::get<3>(tup2) << ")" << '\n';
              std::cout << "       variables: " << first << "  " << second << "  " << third << "  " << fourth << '\n';
            
              std::cout << '\n';
            
              first = 1;
              second = 2;
              third = 3;
              fourth = 4;
            
              int a;
              int b;
            
              // bind the 2th and 4th argument to a and b
              std::tie(std::ignore, a, std::ignore, b)= tup2;
            
              // print the values
              std::cout << "a: " << a << '\n';
              std::cout << "b: " << b << '\n';
            
              std::cout << '\n';
            
              // will also work for std::pair
              std::tie(a, b)= std::make_pair(3001, 3002);
            
              // print the values
              std::cout << "a: " << a << '\n';
              std::cout << "b: " << b << '\n';
            
              int res1;
              double res2;
              char res3;
            
              std::tie(res1, res2, res3) = returnTuple();
            
              std::cout << '\n';
            
                // print the values
              std::cout << "res1: " << res1 << '\n';
              std::cout << "res2: " << res2 << '\n';
              std::cout << "res3: " << res3 << '\n';
            
            
            }
            
            RainerRainer
            Keymaster
                Up
                0
                Down
                ::

                Thanks a lot.
                I fixed it.

                in reply to: Naming convention in visitor pattern #628684
                RainerRainer
                Keymaster
                    Up
                    0
                    Down
                    ::

                    I would go one step further. visit_car_elements should be renamed to accept and also std::visit should be called std::accept. The second renaming is not possible.

                    in reply to: Adding the type to the Signature of a function #628666
                    RainerRainer
                    Keymaster
                        Up
                        0
                        Down
                        ::

                        So far, I never saw this syntax. Clang give an error message using the following code (https://godbolt.org/z/s15WM3TY6):

                        enum myEnum{};
                        enum class myEnumClass{};
                        class myClass{};
                        
                        void myFunction(enum myEnum a_myEnum);                  // (1)
                        void myFunction(enum class myEnumClass a_myEnumClass);  // (2)
                        void myFunction(class myClass a_myClass);
                        
                        int main() {
                            static_cast<enum myEnum>(0);
                            static_cast<enum class myEnumClass>(0);
                        }
                        

                        (1) and (2) are references to enumerations, but only (1) is valid. The same holds for the use of enum in the main function.

                        in reply to: Question about covariant return types #628641
                        RainerRainer
                        Keymaster
                            Up
                            0
                            Down
                            ::

                            I asked Alf P. Steinbach, moderator of a C++ group: Why do smart pointers not support the covariant return type?

                            Here is his answer: “Well, because C++ functions return by value, so an override must return something of the same physical size. And raw pointers and references to class type objects are all the same size.” On the contrary, std::std::unique_ptr<Base> and a std::unique_ptr<Derived> must not have the same physical size.

                            in reply to: Question about covariant return types #628633
                            RainerRainer
                            Keymaster
                                Up
                                0
                                Down
                                ::

                                Exactly. Smart pointers do not support the covariant return type. For me, this is a design flaw because you should use smart pointers instead of pointers.

                                in reply to: Strategized locking – Runtime vs. compile time #628627
                                RainerRainer
                                Keymaster
                                    Up
                                    1
                                    Down
                                    ::

                                    I wrote that compile-time polymorphism produces wordy error messages and is challenging. This changes drastically with C++20 and C++23.

                                    • C++20: Concepts make the error messages very pointy
                                    • C++23: Deducing This removes the curious and recurring part from CRTP
                                    RainerRainer
                                    Keymaster
                                        Up
                                        0
                                        Down
                                        ::

                                        Thanks a lot. I fixed it.

                                        in reply to: Use cases for CRTP #602128
                                        RainerRainer
                                        Keymaster
                                            Up
                                            0
                                            Down
                                            ::

                                            You mentioned the use-cases I have in mind: static polymorphism and mixin classes. Fedor Pikus is a big fan of CRTP. When you want to see what’s possible, read his book “Hands-On Design Patterns with C++“.

                                            in reply to: Methods for static polymorphism (class level) #602127
                                            RainerRainer
                                            Keymaster
                                                Up
                                                0
                                                Down
                                                ::

                                                I regards type erasure not as static polymorphis because the is a virtual call involved. When you want to have static polymorphism, you have only generic programming. Essentially, you can do it in two ways:

                                                • Use templates, best combined with concept in C++20.
                                                • Use CRTP: With deducing this in C++23, this is not curious anymore. I will add a example in the next days.

                                                 

                                                RainerRainer
                                                Keymaster
                                                    Up
                                                    0
                                                    Down
                                                    ::

                                                    Option 1 and 2 are used in embedded environment, in which memory allocation is not allowed but you want to have virtuality.

                                                    in reply to: Trouble getting visitOverload.cpp to compile #588759
                                                    RainerRainer
                                                    Keymaster
                                                        Up
                                                        0
                                                        Down
                                                        ::

                                                        This is strange. I should have the same configuration: https://godbolt.org/z/a6vP1zvcr. I played with in on my local PC.

                                                        RainerRainer
                                                        Keymaster
                                                            Up
                                                            0
                                                            Down
                                                            ::
                                                            1. I see no issue with the example. The function cloneMe is the new owner of interface and creates a clone of it. After the cloneMe call in the main function, the interface is new initialized. Of course, instead of taking the std::unique_ptr by value, cloneMe could take it by const reference. In this case, cloneMe would not own the interface, but only borrow it.
                                                            2. You are right.  I will add a virtual destructor to the solution. The program has undefined behavior.
                                                            in reply to: Question about covariant return types #575240
                                                            RainerRainer
                                                            Keymaster
                                                                Up
                                                                0
                                                                Down
                                                                ::

                                                                Your following example (https://godbolt.org/z/je5nnne6s) should show the differences. Derived uses a covariant return type, but Derived2 not. To use the return type from Derived2’s clone functions as type Derived2 and not Base, you have to downcast it with a dynamic_cast explicitly.

                                                                struct Base {
                                                                    virtual Base* clone() const{
                                                                        return new Base(*this);
                                                                    }
                                                                    virtual ~Base() = default;
                                                                };
                                                                
                                                                struct Derived : Base {
                                                                    Derived* clone() const override {
                                                                        return new Derived(*this);
                                                                    }
                                                                    void test() {};
                                                                };
                                                                
                                                                struct Derived2 : Base {
                                                                    Base* clone() const override{
                                                                        return new Derived2(*this);
                                                                    }
                                                                    void test() {};
                                                                };
                                                                
                                                                int main() {
                                                                
                                                                    Derived der;
                                                                
                                                                    Derived* d1 = der.clone();
                                                                    d1->test();
                                                                
                                                                    Derived2 der2;
                                                                    // Derived* d2 = der2.clone(); ERROR
                                                                    Base* b2 = der2.clone(); 
                                                                    Derived2* d2 = dynamic_cast<Derived2*>(b2);
                                                                    d2->test();
                                                                
                                                                }
                                                                
                                                              Viewing 15 posts - 121 through 135 (of 349 total)