Forum Replies Created

Viewing 15 posts - 91 through 105 (of 349 total)
  • Author
    Posts
  • in reply to: C++ newsletters and magazines #629252
    RainerRainer
    Keymaster
        Up
        0
        Down
        ::

        I already added https://www.cppstories.com/ to the blogs. I will extend the resources page with a newsletter list.

        in reply to: Constructor parameters #629249
        RainerRainer
        Keymaster
            Up
            1
            Down
            ::

            I used const&, but I may change it because there is one significant advantage of copying and moving it: no sharing. Meaning, when you use your class in a concurrent environment and take it by const&, you have to protect it.

            To put it the other way around. I will only use a const& if I’m 100% sure my code will never run in a concurrent environment. In this regard, the rules F.15 (proposes const&) and CP.1 (CP.1: Assume that your code will run as part of a multi-threaded program) contradict.

            in reply to: complex initialization #629248
            RainerRainer
            Keymaster
                Up
                0
                Down
                ::

                Your question is too general. I only can answer them in a generic way.

                My first impression is that a too complex constructor is a code smell. The Core Guidelines provide a few rules about constructors:

                • C.41: A constructor should create a fully initialized object
                • C.42: If a constructor cannot construct a valid object, throw an exception
                • C.44: Prefer default constructors to be simple and non-throwing
                • C.45: Don’t define a default constructor that only initializes data members; use member initializers instead
                • C.49: Prefer initialization to assignment in constructors
                • C.51: Use delegating constructors to represent common actions for all constructors of a class

                These rules should give the first idea and help simplify the complex construction, but I have an additional remark missing in the core guidelines.

                • Maybe, your class has too many responsibilities. Create additional class or inner classes. This makes your initial constructor leaner because you delegate construction to other classes.
                • Similarly to C.51, use delegating constructors if possible or, as you mentioned, delegate the construction job to a factory.
                in reply to: abstract class #629241
                RainerRainer
                Keymaster
                    Up
                    1
                    Down
                    ::

                    An abstract class is similar to an interface. It defines behavior which the derived classes must (pure virtual) or can (virtual) implement. An abstract class should not have attributes. It should only have member functions. Attributes can not be virtual.

                    in reply to: pure virtual function, virtual destructor #629240
                    RainerRainer
                    Keymaster
                        Up
                        2
                        Down
                        ::

                        You need a virtual destructor when you want to have virtual destruction behavior. This means that you destruct a derived object using the interface of the base class. A virtual default destructor cannot be pure, because it is always implicit called, when you destruct a derived object through an abstract base class.

                        RainerRainer
                        Keymaster
                            Up
                            1
                            Down
                            ::

                            Defining a static outside a class was a limitation of the C++ standard. Using static int a; was only a declaration. This limitation is gone with C++17. No, you can define a static inside a class: inline static int a{};

                            class Test {
                            
                                static int a;        // declaration
                                inline static int b; // definition
                            };
                            
                            in reply to: template parameter + enable_if #629230
                            RainerRainer
                            Keymaster
                                Up
                                0
                                Down
                                ::

                                This is a viable solution. Now, this works because you only overloaded check once.

                                in reply to: switch vs. std::map #629227
                                RainerRainer
                                Keymaster
                                    Up
                                    0
                                    Down
                                    ::

                                    Your first concern should not be performance but readability. The main difference is that the switch statement is a compile-time decision. You have to code it. On the contrary, a std::map is a run-time decision because you can add at run time additional cases. From the performance point of view, you should use instead of the std::map a std::unordered_map. A std::unordered_map provides constant access time but a std::map only logarithmic access time.

                                    I discussed all options in two of my previous posts:

                                    in reply to: template parameter + enable_if #629221
                                    RainerRainer
                                    Keymaster
                                        Up
                                        1
                                        Down
                                        ::

                                        This is probably a side effect of the two phase lookup of templates (two-phase_lookup). This is important, when you have dependent names (Dependent Names). What is a dependent name? A dependent name is essentially a name that depends on a template parameter.

                                        This is the essential difference:

                                        • Non-dependent names are looked up at the point of the template definition.
                                        • Dependent names are looked up at the point of the template instantiation.

                                        Your first example exampleWithExtraTemplateParam uses a dependent name.

                                        Your second example exampleWithoutExtraTemplateParam uses a non-dependent name.

                                        At the point of template definition, the compiler assumes that both functions return a boolean. It considers both function in isolation. This is why the second example fails. This is a redeclaration of a function template.

                                        typename std::enable_if_t<std::is_same_v<T, bar>, bool> check(){
                                            return true;
                                        }
                                          
                                        typename std::enable_if_t<!std::is_same_v<T, bar>, bool> check(){
                                            return false;
                                        }
                                        

                                        On the contrary, at the point of template instantiation, the compiler knows that only one version is created.

                                        From the compiler definition, the compiler regards your program as:

                                        #include <iostream>
                                        #include <type_traits>
                                        
                                        class foo;
                                        class bar;
                                        
                                        template<class T>
                                        struct is_bar {
                                            bool check(){
                                                return true;
                                            }
                                          
                                            bool check(){
                                                return false;
                                            }
                                        
                                        };
                                        
                                        int main() {
                                            is_bar<foo> foo_is_bar;
                                            is_bar<bar> bar_is_bar;
                                            if (!foo_is_bar.check() && bar_is_bar.check())
                                                std::cout << "It works!" << std::endl;
                                        
                                        }
                                        

                                        This gives you the same error message.

                                        in reply to: Static_assert fails within consteval function #629188
                                        RainerRainer
                                        Keymaster
                                            Up
                                            0
                                            Down
                                            ::

                                            You need lazy evaluation. For example, short circuit evaluation  helps here. Boolean operators in C++ apply it. Short circuit evaluation means, essential, that the evaluation of a boolean expression stops if the result is already given.

                                            Here is the program having the same workflow as yours.

                                            #include <iostream>
                                            
                                            constexpr int foo(int v1, int v2) {
                                              constexpr int x = 9;
                                              constexpr int y = 9;
                                              if constexpr (!std::is_same<decltype(v1), int>::value) {
                                                static_assert(std::is_same<decltype(v1), int>::value || (v1 != v2));
                                                return 1;
                                              }
                                              return 2;
                                            }
                                            
                                            int main() {
                                              constexpr int f = foo(1, 1);
                                              static_assert(f == 2);
                                            }
                                            

                                            I used the static_assert inside the constexpr if, but you can also use it as a standalone feature: static_assert(std::is_same<decltype(v1), int>::value || (1/0));

                                            Another way to achieve this would be to put your static_assert inside the member function of a class template. They are only created if used. I wrote more about it here: Surprise Included: Inheritance and Member Functions of Class Templates

                                             

                                            in reply to: Static_assert fails within consteval function #629187
                                            RainerRainer
                                            Keymaster
                                                Up
                                                0
                                                Down
                                                ::

                                                In the case of a consteval function, just use an if instead of a static_assert.

                                                #include <iostream>
                                                #include <string>
                                                
                                                consteval auto doubleMe( int val1, int val2 ) noexcept
                                                 {
                                                    constexpr int a = 10;
                                                    constexpr int b = 10;
                                                    
                                                    static_assert( a == b, "OK");
                                                    if (val1 == val2) // do something at compile time; for example std::expected
                                                
                                                  return 2 * val1;
                                                }
                                                
                                                int main() {
                                                
                                                    auto res = doubleMe(1010, 1010);
                                                    ++res;
                                                }
                                                
                                                in reply to: Initialization of Raw Strings Literals #629149
                                                RainerRainer
                                                Keymaster
                                                    Up
                                                    1
                                                    Down
                                                    ::

                                                    The delimiter specifies the content of the raw string.

                                                    • Default delimiter:
                                                      • Begin: R”(
                                                      • End: )”
                                                    • Special delimiter:
                                                      • Begin: R”TRENNER(
                                                      • End: )TRENNER”

                                                    TRENNER can be “almost” any sequence of characters. The delimiter allows you to use )” inside the raw string which would by default end the raw string.

                                                    in reply to: Initialization of Raw Strings Literals #629101
                                                    RainerRainer
                                                    Keymaster
                                                        Up
                                                        1
                                                        Down
                                                        ::

                                                        Raw Strings support an extended syntax. TRENNER can be 16 characters long. Now, you can use a string termination symbol ()”) inside a raw string. Consider raw3 in the following program:

                                                        #include <iostream>
                                                        #include <string>
                                                        
                                                        int main(){
                                                        
                                                          std::cout << '\n';
                                                        
                                                          std::string nat = "C:\temp\newFile.txt";
                                                          std::cout << nat << '\n';
                                                        
                                                          // including \t \n
                                                          std::string raw1 = std::string(R"(C:\temp\newFile.txt)");
                                                          std::cout << "\n" << raw1 << '\n';
                                                        
                                                          // including \t \n and using a delimiter
                                                          std::string raw2 = std::string(R"TRENNER(C:\temp\newFi)"le.txt)TRENNER");
                                                          std::cout << "\n" << raw2 << '\n';   
                                                        
                                                          std::cout << '\n';
                                                        
                                                        }
                                                        
                                                        in reply to: User-defined literal, overload operator #629100
                                                        RainerRainer
                                                        Keymaster
                                                            Up
                                                            0
                                                            Down
                                                            ::

                                                            I don’t know if I get your question.

                                                            In general, you should only use friend if necessary, because friend breaks encapsulation.

                                                            Friendship cannot be inherited and is not transitive.

                                                            1. If a class Base grants friendship to a class Derived, a from class Base derived class Derived is not automatically a friend of Base.
                                                            2. If class B is a friend of class A and Class C is a friend of class B, class C is not automatically a friend of class A.

                                                            Friendship is pretty special for templates. You can read it here: The Special Friendship of Templates

                                                            RainerRainer
                                                            Keymaster
                                                                Up
                                                                1
                                                                Down
                                                                ::

                                                                You are right, but this is regarded as a code small. See the C++ Core Guidelines: Enum.8: Specify enumerator values only when necessary

                                                              Viewing 15 posts - 91 through 105 (of 349 total)