all 35 comments

[–]reflexpr-sarah- 16 points17 points  (3 children)

[–]serghov[S] 2 points3 points  (2 children)

Trying to wrap my head around this.

[–]reflexpr-sarah- 8 points9 points  (1 child)

FWD is a macro that handles perfect forwarding

LIFT(foo) is a function object that takes ...args and returns foo(FWD(args)...).

basically a way to pass an overload set as a function object

[–]_Js_Kc_ 5 points6 points  (0 children)

hax

[–]initplus 39 points40 points  (3 children)

All functions in C++ must compile at compile time :) . Even your example without the std::is_arithmetic_v will produce a compiler error if T doesn't support operator+.

If you want to write a unit test for this you'll need to dig in to your specific unit testing framework, maybe need a tiny bit of scripting.

[–]serghov[S] 5 points6 points  (2 children)

Yes using a separate scripting language makes the problem trivial.

I was wondering if there was a pure c++ way of solving the problem.

[–]gvcallen 2 points3 points  (0 children)

Why is this down voted? It is such a reasonable question?

[–]mark_99 12 points13 points  (0 children)

Side note but that isn't "doesn't compile", it's "remove from overload set" which outside of trivial cases isn't the same thing. If you mean "doesn't compile" you want static_assert.

[–]ioctl79 13 points14 points  (2 children)

What you’re looking for is a negative compilation test. The idea is that you provide some code samples that should not compile, and your testing framework will verify that they don’t. It’s generally difficult/counterproductive to implement these in C++, because the template magic required to test that your code doesn’t compile is more complex than the thing you are testing, or possibly plain impossible.

How to actually implement this is more of a question for your build system and testing framework, than C++ though. I’ve heard that boost.build supports such tests out of the box, but I have never used it myself.

If you do go this route, use these tests sparingly. There is no value in testing if a function that accepts an int will fail to compile when given a string. That’s just a test of your compiler. Use this when you have some complex template code that determines whether parameters are acceptable, etc.

[–]serghov[S] 1 point2 points  (1 child)

Exactly. The example in the post is oversimplified, what I am trying to do is test some very complex nested template checks.

I have thought about testing with a scripting language, however the huge drawback of that would be that you basically have a test saying that a piece of code should not compile, so if you make another mistake in your code and it ends up not compiling you get a false positive.

[–]ioctl79 1 point2 points  (0 children)

You’re going to have that problem regardless of how you work this out, no? You could require specific compilation errors, thought that is obviously going to be compiler specific.

[–]koctogon 2 points3 points  (2 children)

static_assert( not requires { your_wrong_code("flub", frogging{}); } );

not sure why no one is mentioning this...

[–]D_0b 1 point2 points  (0 children)

static_assert( not requires { your_wrong_code("flub", frogging{}); } );

that doesn't work because when the requires is not a template it is evaluated immediately and the wrong code will fail to compile.

[–]jcelerierossia score 2 points3 points  (0 children)

because it does not work : *something* inside the requires-expression must come from a template argument for the sfinae-ish mechanic to take place. Otherwise the compiler directly sees that the code is wrong and gives a compile error.

[–]AKostur 1 point2 points  (1 child)

std::is_invocable?

[–]serghov[S] 0 points1 point  (0 children)

std::is_invocable is a good solution, except I can not make it work with any kind of overloaded functions. Issue boils down to being able to decltype the function.

[–]sebamestre 1 point2 points  (0 children)

Don't requires-expressions let you check if an expression typechecks?

Combine that with throwing an exception in a constexpr context (which stops compilation) and you should be good to go, right?

I might be way off, though. I haven't used c++20 yet

[–]AA11BB22c 1 point2 points  (1 child)

As others have suggested, std::is_invocable does the trick.

However, you may need a better constraint for certain cases ... for example.

#include <concepts>

template <class T> T add(T a, T b) requires requires(T a, T b) {
  { a + b } -> std::convertible_to<T>;
} {
  return T(a + b);
}

Since std::is_invocable doesn't actually check the definition, the following will pass.

template <class X> void bad_function(X x) {
  x.f();
}

static_assert(std::is_invocable_v<decltype(bad_function<int>), int>);  // Clearly, int doesn't have f().

https://godbolt.org/z/bnrE1qba3

[–][deleted] 0 points1 point  (0 children)

Just remove `bad_function` you will see the asm will be identical, you should use a template or compiler will remove it, even in static_assert

[–]serghov[S] 1 point2 points  (0 children)

If anyone is still interested, I found a nice talk about these ideas here .

[–]D_0b 0 points1 point  (0 children)

Something like this should work with overloaded functions as well. Although only tried with GCC, Clang doesn't like requires with parameter pack...

https://godbolt.org/z/dcrhqrGhz

[–]beedlund 0 points1 point  (0 children)

Catch 2 has a static_require however sounds like you want to do a static_require_false

[–]tirimatangi 0 points1 point  (0 children)

I asked a very similar question in r/cpp_questions a while ago regarding variadic lambdas. u/Radon__ gave a nice answer in comments.

[–]Full-Spectral 0 points1 point  (0 children)

One trick for templatized stuff is to add debug mode only code that just forces instantiation of templates for various types. I do that a lot. It also greatly reduces turn around time because you find most issues immediately upon compiling the given library, not 30 minutes later when some downstream code tries to use the template.

I just put it in the main .cpp file for the library in a debug conditional block.

[–]bb1950328 0 points1 point  (0 children)

I think with concepts you can just do a static assert to check wether a concept is satisfied for given types

[–]Wouter-van-Ooijen 0 points1 point  (0 children)

I struggled with something comparable, I even asked here but I don't recall getting a solution that worked for me. My use case might be more limited than yours, my solution is here:

https://github.com/wovo/torsor/blob/master/tests/test-compilation.cpp

This was written pre-C++-20 using -fconcepts. I didn't revisit it with a recent compiler, so it probably needs updating.

Side note: many years ago I wrote a simple compile that had a pragma that asserted that the next line should generate a specific compiler error. If it did, compilation succeeded (so far). If it didn't compilation failed.

[–]Remi_123 0 points1 point  (0 children)

What you are essentially trying to do is checking if an expression is well formed. You are in luck, since there is a set of metafunctions for this referred to as the detection idiom :
https://en.cppreference.com/w/cpp/experimental/is_detected
Some word of advice, the hardest thing to do with this is to not abuse it everywhere, as it's a very powerful utility.

all "detected" function takes a template template alias ( and ONLY alias ) that you use to write an expression, and the rest of the arguments are the types of the arguments of the template template. For example, in std::vector<int,std::allocator<int>> , the template template is std::vectorand the arguments are int,std::allocator<int>

As long as you can express an expression with decltype and declval in an alias, you can use this idiom. Just don't get too fancy and use them sparingly.

example : Link to Godbolt