26

Loki's solution does not enforce the order in which the function calls are performed, because the order in which function arguments are evaluated is unspecified. Here's a C++14 solution that ensures the function is called from left to right: #include <cstddef> #include <tuple> #include <utility> template <typename Tuple, typename F, ...


17

Here is my lightweight solution that involves no operations at run time: template<typename T> struct type { static void id() { } }; template<typename T> size_t type_id() { return reinterpret_cast<size_t>(&type<T>::id); } struct A { }; int main () { cout << type_id<int>() << " " << type_id<int*>...


17

template <typename Less, typename T, typename... Ts> constexpr const T& min(Less less, const T& a, const T& b, const Ts&... rems) { This function requires a minimum of 2 elements. A minimum element will exist if the user provides a single argument variadic list. Consider handling that. auto& min1 = min(std::less<>{}, 4, 5); ...


16

Let me collect a couple of thoughts here. Aggregate initialization currently works like this: array2d<int, 2, 2> a{{1, 2, 3, 4}}; but wouldn't it be favorable to allow for array2d<int, 2, 2> a{{1, 2}, {3, 4}}; std::array::at performs bound checking and throws upon an out of bounds index. When your intention is to stick with the std::array ...


15

I believe I can help with these things: Obliterate macros Obliterate raw arrays Macros can be replaced with std::integer_sequence (C++14), and raw arrays can be replaced with std::array (C++11). #include <array> #include <utility> template <typename T, T... Is> constexpr auto gen_primes_helper(std::integer_sequence<T, Is...>) { ...


12

Below is how I would clean this up, or maybe partially re-write [live example]: // helpers template <typename T> struct id { using type = T; }; template <typename T> using type_of = typename T::type; template <size_t... N> struct sizes : id <sizes <N...> > { }; // choose N-th element in list <T...> template <size_t ...


12

This looks nice! Two issues I see here, When compiling your template with clang, it refuses the if constexpr dispatch for every recursive instantiation with sizeof...(rems) > 1, e.g. error: constexpr if condition evaluates to 2, which cannot be narrowed to type bool [-Wc++11-narrowing] gcc seems to accept this, but the fix is quite simple, just be ...


11

I might have a number of minor stylistic comments but this is not important. What is important is the desired function decorate(): template <typename S> using result = typename std::result_of <S>::type; template <template <typename> class E, template <typename> class... D> struct decorate_impl { template <typename A, ...


10

It looks pretty clean to me. The copy constructor doesn't have to be explicitly declared, you could = default it or just omit. You shouldn't fill() the array. It is already default constructed, so that's just duplicated work. The default constructor again could be = default or omitted. Actually, maybe could provide an explicit constructor that takes a fill ...


10

Write Less Code The main problem I see with this solution is that you're writing so much more code than you need to to accomplish the task at hand. First of all, your copy constructor is broken since you can't use an array as an initializer. But really, you don't need it at all. The default copy constructor is fine. Array(const Array&) = default; ...


10

One reason you think you require a lot of helper metafunctions is that you haven't clearly separated the code for solving the problem (filtering a list) from the code for testing the solution (e.g. list_rename and A, B, C). Your actual solving the problem code, with redundant comments and newlines removed, boils down to this: template <typename ...> ...


10

IndexOf can probably be a nested type of FlagSet, unless you intend for that to be part of the public interface. using underlying_t = std::enable_if_t<std::is_integral_v<U>,U>; Are you sure SFINAE is what you want to do here? It would probably make more sense to static_assert that U is integral. At the same time, you might also want to static ...


10

A few issues: Functions defined in the class in the header are inline by default, so there's no need to use the keyword everywhere. Use std::copy, not std::memcpy. It's just as fast (if not faster), and doesn't have memcpy's trivially copyable requirement (currently there's no check to make sure the objects stored in the class are trivially copyable). ...


9

It is becoming really good, but there are still a few things that can be done: There already is a standard way to "clean" a type: std::decay. It does a little bit more than just removing the reference and the const qualification though, but it does basically what you need. Therefore, you can totally get rid of CleanType and use std::decay instead: using ...


9

In C++14, it's possible to implement a tuple in a very concise way. However, you lose some functionality of std::tuple (constexprness and some perfect forwarding) because of some limitations of lambdas. The basic idea is to use a lambda capture as a fast compiler-generated struct. Here's a naive implementation just to give you the idea, but you should look ...


9

Use of T for accumulator and result I question the decision to use a template parameter T as the result and accumulator type. Especially in the calculation of the variance, using T as accumulator and mean value will cause significant errors in the calculated standard deviation and variance. The mean value may be off by at most \$\lim_{x\rightarrow 1}x\$. I ...


9

It works well, according to my simple test program: #include <functional> int main() { return min(std::less<int>(), 2, 0, 3); } I suggest that when you present code for review, you include the tests, too - I imagine that your testing is much more thorough than mine, and I'm too lazy to re-create the full suite. It also helps reviewers ...


9

C++ 17 Why limit yourself to C functions? DynamicTest(OutputType (*testfunc)(InputType), OutputType (*trustedfunc)(InputType)) I would declare this as: DynamicTest(std::function<OutputType(InputType)>&& testfunc, std::function<OutputType(InputType)>&& trustedfunc) Also the C++ versions for function declarations are easier to ...


8

Re. the algorithm, IMO it looks safe, with only two caveats: I'm not sure that it's thread-safe. It looks safe, because of the "one-definition rule". I worried that if multiple source files ('translation units') invoke TypeID<int*>::value() they might each get their own copy of the type; however I think that the "one-definition rule" requires the ...


8

Usage of "fat" templates I would try to avoid using full-blown class templates when there's an elegant alternative solution with alias templates or constexpr functions. Note that I didn't measure this, so take it with a grain of salt: lightweight constexpr functions and alias template can be faster to instantiate. Using constexpr functions might reduce the ...


8

To reduce redundancy, I'd probably move the check for the inputs being the same size into a function template by itself, and just invoke that from the other three: template <typename T> void check_size(std::vector<T> const &a, std::vector<T> const &b) { if (a.size() != b.size()) throw std::domain_error("vector addition ...


8

Your current strategy will cause more reallocations than you need to, which is not efficient. You already have all of your vector parameters, so you simply need to get their size, and reserve that amount for the output vector. template<typename V1, typename V2, typename... Rest> std::size_t get_reserve_amount( V1 const& v1, V2 const& v2, Rest ...


8

I think there are two flaws with this function; the first is in conception, and the second is in implementation. The conception problem is this: What does genuine_apply really do? You pass it a callable and an argument. If the argument is a tuple-like object, you expand it and pass its elements as separate arguments to the callable. If you pass it a non-...


8

Your implementation is excellent! I can hardly find any problems. I was amazed how simple a conforming implementation of any can be. And I wholeheartedly agree with @papagaga's comment. Here's my two cents. I use the N4659, the C++17 final draft, as a reference. Non-conformance (priority: high) Thou Shalt Not Specialize std::swap. Instead, you should ...


8

General design Currently, your function is defined to have "undefined behavior" if the number of arguments is wrong. This is sub-optimal. Checking is trivial in this case, so report the problem in some way instead of producing strange output. I could make it a run-time error, but that would add run-time cost and thus violate C++'s philosophy of ...


8

Are there some cases in std::bind_front that I missed? There are several significant differences between std::bind_front's behavior and your implementations. First, your implementation unconditionally returns a value. But what if the callable in question returned a reference? The behavior is just incorrect. Second, std::bind_front is SFINAE-friendly but ...


8

Avoid special cases A lot of problems come from the fact that you have slightly different ways to construct a 2D point and to get its elements than you have for an arbitrary dimensional point. You should avoid that first, this will make your life much easier. Here is a class Point that supports getX() and getY() with compile-time checking that the size of ...


8

Assignment using [] operator If you have a look at your overload of [] T operator[](size_t k) const { return elements[k]; } You are creating a copy. What you should do is returning a reference - & otherwise, you can't do something like Point< int, 3 > p({1,2,3}); p[0] = 5; // Erorr: Expression must be a modifiable value ...


7

I need a bit to look into a cleaner decorator pattern, but three technicalities immediately jump out at me. Accepting a user defined value as const implies that your methods should probably be taking const-references. void f(const T) will make a copy of the value passed to it. void f(const T&) will not, yet it maintains the restriction that T cannot be ...


7

Generally speaking, it's good and works great (version 2 seems better). There are some things that could be changed/added though: In C++, ranges tend to be [begin, end) ranges. Your compile-time integer ranges are actually [begin, end] ranges. The last element should not be included in the range. Therefore, you change this code: template<int S, int E>...


Only top voted, non community-wiki answers of a minimum length are eligible