Forum Replies Created
-
AuthorPosts
-
::
Here are three variations. All three use the fact that you can get the underlying type of a container Cont with Cont::value_type.
- Derive the type from the container:
template <typename Cont> void doTheSame(Cont cont, typename Cont::value_type t){
- Use static_assert in the algorithm:
template <typename Cont, typename T> void doTheSame(Cont cont, T t){ static_assert(std::is_same<typename Cont::value_type, T>::value, "Must be same type");
- Use the concept std::same_as in C++20
template <typename Cont, typename T> requires std::same_as<typename Cont::value_type,T> void doTheSame(Cont cont, T t)
The solutions 2 and 3 do not allow implicit conversion. The types must exactly match. You can study my variations on the Compiler Explorer: https://godbolt.org/z/TW8G7Yvcz.
::The five creational patterns in the book “Design Patterns: Elements of Reusable Object-Oriented Software” use as the running example a maze. I found C++ implementations of the pattern on BartVandewoestyne / Design-Patterns-GoF.
I know the author Bart, because he was one of the proofreaders of my by “The C++ Standard Library“.
::Here are the three examples of rule R.36:
void share(shared_ptr<widget>); // share -- "will" retain refcount (1) void reseat(shared_ptr<widget>&); // "might" reseat ptr (2) void may_share(const shared_ptr<widget>&); // "might" retain refcount (3)
- The function share is an additional owner of the widget.
- The function reseat may change the widget, shared by all owners of it.
- The function may_share is not an owner of the widget. It is only borrowed. This is the general semantics of a function taking it argument by pointer or by reference. I see no added value here. A raw pointer to the widget or a reference would also be fine.
::So far, I’m in the process of analyzing your program. I, therefore, simplified it a bit. Here are my first thoughts.
Your program has undefined behavior. The function get_cell returns a reference to a local: https://godbolt.org/z/58hWbYsM5 => Your Grid should be a std::vector<std::vector<Cell*>> for your strategy.
Now, get_cell returns a value: https://godbolt.org/z/jxEGqza8K. This is fine.
::I don’t know why. I can only quote cppreference.com: “If T is a const-qualified type (that is, const, or const volatile), provides the member constant value equal to true. For any other type, value is false.”
::You declared point of the correct type. This must return true.
Typically, you do it the other way around. You have a member pointer, and you want to ask what kind of pointer this is: member object pointer or member function pointer.
I modified your example and asked for the pointer types of A::a, and A::f.
#include <iostream> #include <type_traits> struct A { int a; int f(int) { return 2011; } }; int main() { std::cout << std::boolalpha << '\n'; A a; std::cout << "std::is_member_pointer<decltype(&A::a)>::value: " << std::is_member_pointer<decltype(&A::a)>::value << '\n'; std::cout << "std::is_member_pointer<decltype(&A::f)>::value: " << std::is_member_pointer<decltype(&A::f)>::value << '\n'; std::cout << '\n'; std::cout << "std::is_member_object_pointer<decltype(&A::a)>::value: " << std::is_member_object_pointer<decltype(&A::a)>::value << '\n'; std::cout << "std::is_member_object_pointer<decltype(&A::f)>::value: " << std::is_member_object_pointer<decltype(&A::f)>::value << '\n'; std::cout << '\n'; std::cout << "std::is_member_function_pointer<decltype(&A::a)>::value: " << std::is_member_function_pointer<decltype(&A::a)>::value << '\n'; std::cout << "std::is_member_function_pointer<decltype(&A::f)>::value: " << std::is_member_function_pointer<decltype(&A::f)>::value << '\n'; std::cout << '\n'; std::cout << "std::is_same<int A::*, decltype(&A::a)>::value: " << std::is_same<int A::*, decltype(&A::a)>::value << '\n'; std::cout << "std::is_same<double A::*, decltype(&A::a)>::value: " << std::is_same<double A::*, decltype(&A::a)>::value << '\n'; std::cout << '\n'; std::cout << "std::is_same<int (A::*)(int), decltype(&A::f)>::value: " << std::is_same<int (A::*)(int), decltype(&A::f)>::value << '\n'; std::cout << "std::is_same<int (A::*)(double), decltype(&A::f)>::value: " << std::is_same<int (A::*)(double), decltype(&A::f)>::value << '\n'; }
Here is the corresponding compiler explorer example: https://godbolt.org/z/vj8MWvP4M.
::There is no way to get output at compile time.
You can either
- enforce a compile time error with static_assert (C++11) or Concepts (C++20)
- visualize the template instantiation process with C++ Insights or the Metashell
::Here are my thoughts:
-
- Use non-type template parameters:
template <int T, int... Ts > constexpr int testIntSum() { int initialValueIncreased{ T }; auto doSumOperation = [&](const auto& singleOtherValue) { //filter out the non-arithmetic types if constexpr( std::is_arithmetic_v< std::remove_reference_t< decltype( singleOtherValue ) > >) { initialValueIncreased += singleOtherValue; } }; (..., doSumOperation(Ts)); return initialValueIncreased;
- Use Fold Expressions in C++17: https://www.modernescpp.com/index.php/from-variadic-templates-to-fold-expressions
- Use a std::initializer_list:
#include <iostream> #include <numeric> #include <initializer_list> template <typename T> T sum(std::initializer_list<T> args) { return std::accumulate(args.begin(), args.end(), T{}); } int main() { std::cout << sum({1, 2, 3, 4, 5}); }
- Use a concept in C++20:
constexpr std::integral auto testGenericSum(const std::integral auto& initialValue, const std::integral auto&... otherValues) { std::integral auto initialValueIncreased{ initialValue }; auto doSumOperation = [&](const auto& singleOtherValue) { //filter out the non-arithmetic types if constexpr( std::is_arithmetic_v< std::remove_reference_t< decltype( singleOtherValue ) > >) { initialValueIncreased += singleOtherValue; } }; (..., doSumOperation(otherValues)); return initialValueIncreased; }
Only for completeness, but I don’t suggest this. You can also define a concept for a concrete type. Additionally, I decayed in my example on the int:
#include <type_traits> template <typename T> concept int_ = std::is_same_v<std::decay_t<T>, int>; int main() { static_assert(int_<int>, "no int"); static_assert(int_<int&>, "no int"); static_assert(int_<const int>, "no int"); }
- Use non-type template parameters:
::You have to ensure, that a header or an entity is only included once in a translation unit. ⇒ You use include guards:
#ifndef INCLUDE_GUARD_H #define INCLUDE_GUARD_H #include <myHeader.h> template < class T > constexpr bool is_arithmetic_v = is_arithmetic<T>::value; #endif /* INCLUDE_GUARD_HH */
You have only the guarantee that the variable is_arithmetic_v is used once in one translation unit. Your program may have more than one translation unit. Consequentially, you have more than one usage of the variable is_arithmetic_v.
Here is the issue. Due to the internal linkage of the variable is_arithmetic_v, the variable is_arithmetic_v has more than one definition. This violates the One Definition Rule (ODR) and is undefined behavior.
An inline variable essentially means:
- This entity might be defined in multiple translation units.
- All those definitions are identical.
- Merge them into one definition at link time.
21. September 2022 at 05:54 in reply to: Video on week 17 template specialization – introspection #8786121. September 2022 at 05:46 in reply to: Week 17 Exercise: introspection with partial and full specialization Wrong Video #87860 - Derive the type from the container:
-
AuthorPosts
