Cleanly report compile-time error from constexpr without exceptions? - c++

I am looking for a way to raise a compile-time error from a constexpr function. Since I am on an embedded system, C++ exceptions need to remain disabled (GCC flag -fno-exceptions). Thus, the default way of error reporting seems to be infeasible.
A possible way described in constexpr error at compile-time, but no overhead at run-time is to call a non-constexpr function, which throws an error if compile-time implementation is forced. However, this solution gives rather unreadable error messages and the implementation is forced to return garbage return values in order to silence "control may reach end of non-void function" warnings.
Is there a better way, which allows to provide a custom error message?
Please note, that I am aware of static_assert and the possibility to convert the function to a template. However, static_assert needs to reassemble the quite complex logic of the switch-blocks of my use-case in order to throw an error, which is error-prone and clumsy.
Example use-case:
constexpr SpiDmaTxStreams spiDmaTxStream(DmaId dmaId, DmaStreamId streamId) {
switch (dmaId) {
case DmaId::DMA_1:
switch (streamId) {
case DmaStreamId::Stream_4:
return SpiDmaTxStreams::Dma1Stream4;
// ...
default:
break;
}
break;
case DmaId::DMA_2:
switch (streamId) {
case DmaStreamId::Stream_1:
return SpiDmaTxStreams::Dma2Stream1;
// ...
default:
break;
}
break;
}
// report compile-time error "invalid DMA-stream combination"
}

One way to trigger a constexpr compile error is to trigger UB. The simplest way to trigger UB is via __builtin_unreachable(). That unfortunately doesn't allow for a message, but we could wrap it in a macro.
As an example this program:
#define CONSTEXPR_FAIL(...) __builtin_unreachable()
constexpr int foo(int a, int b) {
switch (a) {
case 0:
return b;
case 1:
if (b == 2) return 3;
break;
}
CONSTEXPR_FAIL("Mismatch between a and b");
}
int main() {
static_assert(foo(0, 2) == 2, "!");
// constexpr int i = foo(2, 2);
}
Compiles fine on gcc 7.2 and clang 5.0 with c++14. If you un-comment the call to foo(2,2), gcc emits:
<source>: In function 'int main()':
<source>:18:26: in constexpr expansion of 'foo(2, 2)'
<source>:1:50: error: '__builtin_unreachable()' is not a constant expression
#define CONSTEXPR_FAIL(...) __builtin_unreachable()
~~~~~~~~~~~~~~~~~~~~~^~
<source>:12:5: note: in expansion of macro 'CONSTEXPR_FAIL'
CONSTEXPR_FAIL("Mismatch between a and b");
^~~~~~~~~~~~~~
and clang emits:
<source>:18:19: error: constexpr variable 'i' must be initialized by a constant expression
constexpr int i = foo(2, 2);
^ ~~~~~~~~~
<source>:12:5: note: subexpression not valid in a constant expression
CONSTEXPR_FAIL("Mismatch between a and b");
^
<source>:1:29: note: expanded from macro 'CONSTEXPR_FAIL'
#define CONSTEXPR_FAIL(...) __builtin_unreachable()
^
<source>:18:23: note: in call to 'foo(2, 2)'
constexpr int i = foo(2, 2);
^
Does this work for you? It's not quite a static_assert in that the compiler doesn't emit the message for you directly, but the it does get the compiler to point to the correct line and the message is going to be in the call stack.

If you can add a special error value in SpiDmaTxStreams enum... say SpiDmaTxStreams::ErrorValue... I propose another solution, again based on a template struct but with reverted logic: the not-specialized struct and a single specialized version for static_error messagge.
I mean... if you return SpiDmaTxStreams::ErrorValue in case of unacceptable combination
constexpr SpiDmaTxStreams spiDmaTxStream(DmaId dmaId, DmaStreamId streamId) {
switch (dmaId) {
case DmaId::DMA_1:
switch (streamId) {
case DmaStreamId::Stream_4:
return SpiDmaTxStreams::Dma1Stream4;
// ...
default:
return SpiDmaTxStreams::ErrorValue; // <<---- add this
break;
}
case DmaId::DMA_2:
switch (streamId) {
case DmaStreamId::Stream_1:
return SpiDmaTxStreams::Dma2Stream1;
// ...
default:
return SpiDmaTxStreams::ErrorValue; // <<---- add this
break;
}
}
// report compile-time error "invalid DMA-stream combination"
}
You can call spiDmaTxStream() to give value to a template value (caution: code not tested) as follows
template <DmaId I1, DmaStreamId I2,
SpiDmaTxStreams IR = spiDmaTxStream(I1, I2)>
struct foo
{ static constexpr auto value = IR; };
template <DmaId I1, DmaStreamId I2>
struct foo<I1, I2, SpiDmaTxStreams::ErrorValue>
{
// where DmaId::DMA_1/DmaStreamId::Stream_4 is an
// acceptable combination
static_assert( (I1 == DmaId::DMA_1) && (I2 == DmaStreamId::Stream_4),
"your error message here" );
};
and, again, instead of
constexpr value id = spiDmaTxStream(DmaId::DMA_2, DmaStreamId::Stream_1);
you can write
constexpr value id = foo<DmaId::DMA_2, DmaStreamId::Stream_1>::value;
If the dmaId/streamId is unacceptable, spiDmaTxStream() return SpiDmaTxStreams::ErrorValue, so the foo specialized version is activated and the static_error() message is in charge.

Sorry, because you asked a completely different solution, but if
dmaId and streamId are literals or constexpr (enum class members) and the whole function is only expected to work at compile-time
to pass dmaId and streamId as not-template parameter seems to me the wrong way.
It seems to me a lot simpler something as follows (sorry: code not tested)
// generic foo: to force a comprehensible error message
template <DmaId I1, DmaStreamId I2>
struct foo
{
static_assert( (I1 == DmaId::DMA_1) && (I2 == DmaStreamId::Stream_4),
"your error message here" );
};
// specialization with all acceptable combinations
template <>
struct foo<DmaId::DMA_1, DmaStreamId::Stream_4>
{ static constexpr auto value = SpiDmaTxStreams::Dma1Stream4; };
// ...
template <>
struct foo<DmaId::DMA_2, DmaStreamId::Stream_1>
{ static constexpr auto value = SpiDmaTxStreams::Dma2Stream1; };
// ...
So, instead of
constexpr value id = spiDmaTxStream(DmaId::DMA_2, DmaStreamId::Stream_1);
you can write
constexpr value id = foo<DmaId::DMA_2, DmaStreamId::Stream_1>::value;

Related

Determine if string contains a particular character at compile time

I'd like to determine if a string contains a particular character at compile time. I thought I would use std::string_view as it has constexpr methods to do what I want. This is the code:
#include <iostream>
#include <string_view>
using namespace std::literals;
template<std::size_t N>
constexpr bool ContainsAsterisk(const char(&formatString)[N])
{
constexpr std::string_view fmtString{ formatString, N - 1 }; // error C2131: expression did not evaluate to a constant
constexpr bool containsAsterisk = fmtString.find('*') != fmtString.npos;
return containsAsterisk;
}
int main()
{
if (ContainsAsterisk("sdf"))
{
std::cout << "sdf no\n";
}
if (ContainsAsterisk("er*r"))
{
std::cout << "er*r yes\n";
}
std::cout << "done\n";
}
This doesn't compile because of these errors
ConsoleApplication.cpp(9,41): error C2131: expression did not evaluate to a constant
ConsoleApplication.cpp(9,43): message : failure was caused by a read of a variable outside its lifetime
ConsoleApplication.cpp(9,43): message : see usage of 'formatString'
ConsoleApplication.cpp(17): message : see reference to function template instantiation 'bool ContainsAsterisk<4>(const char (&)[4])' being compiled
ConsoleApplication.cpp(10,37): error C2131: expression did not evaluate to a constant
ConsoleApplication.cpp(9,43): message : failure was caused by a read of a variable outside its lifetime
ConsoleApplication.cpp(9,43): message : see usage of 'formatString'
I've done quite a bit of googling, and can't understand what this error is telling me! I don't understand how the variable is being read outside it's lifetime, it's a literal (isn't it?) that I thought would be available at compile time.
Any tips explaining the error and how to fix would be appreciated. Thanks.
You are overcomplicating things. std::string_view can be constructed by const char*:
constexpr bool ContainsAsterisk(std::string_view view) {
// constexpr bool b = view.find('*') != view.npos; // ERROR
return view.find('*') != view.npos;
}
int main() {
constexpr bool b = ContainsAsterisk("123123*"); // OK
}
Why am I getting the error?
According to cppreference, a function can be constexpr if:
there exists at least one set of argument values such that an
invocation of the function could be an evaluated subexpression of a
core constant expression [...]
This means that it's not necessary for a constexpr function to always return a constexpr value, neither is it expected to always receive a constexpr argument. It only makes sure that for some specific set of arguments (a constexpr const char* in thie case), it will give a constexpr return value.
Therefore, a definition that assumes the argument is always constexpr (see ERROR line above) is invalid.
Your code can simply be written as:
template<std::size_t N>
constexpr bool ContainsAsterisk(const char(&formatString)[N])
{
for (auto c : formatString)
{
if (c == '*')
{
return true;
}
}
return false;
}
You don't actually need to use string_view.
Unfortunately I can't explain to you why string_view doesn't work.
You already have answers on how else to do this so I wont add anything more to that but this answer will address
I don't understand how the variable is being read outside it's lifetime, it's a literal (isn't it?) that I thought would be available at compile time.
Yes, a string literal is a compile time constant. The issue here is that a function parameter is not a compile time constant, even if it is initialized from one. To see why that is, lets start with the function
template <auto var>
auto foo()
{
if constexpr (var == 1)
return 1;
else
return 1.0;
}
This function template will have two different return types, but only one of them will ever be used in a specialization so you still follow the rule of one return type per function. Now if we allowed constexpr function parameters like
auto foo(constexpr int var)
{
if constexpr (var == 1)
return 1;
else
return 1.0;
}
This function will either return a int or a double, but you can't have one function that has different return types.

constexpr constructor not called as constexpr for implicit type conversion

I made some code which is capable of dispatching to a function based upon the call-site providing a string associated with a given function (via a tuple of function pointers and a parallel array). Instead of accepting a string directly, the dispatch function accepts a Callable type, where a const char* is convertible to a Callable.
The constructor of Callable is constexpr, and looks up a function from the noted tuple with a basic recursive search. I've verified that the constructor is capable of working correctly and creating a constexpr Callable (example included). Since the dispatch function receives the arguments to pass to the Callable's operator(), I know the expected function signature of the Callable's operator() at the time I create it.
I'm trying to perform two checks at compile-time, when they can be done at compile-time. First, I check that the provided string exists in the pre-defined array of strings, at all. Second, I check that the signature of the function associated with that string matches the expected signature from the tuple of function pointers. I create "friendly" error messages at compile-time by throw()'ing within the constexpr method that looks up the function.
I've verified that by creating a constexpr callable, I get the expected error messages at compile-time. This works. What doesn't work is getting compile-time messages if I use my Dispatcher directly, letting the call-site convert a string into a Callable. I know that when I use runtime parameters, my dispatch function won't be called in a constexpr context - I intentionally didn't make that function constexpr; the point is to call it with runtime values. But I thought that implicit conversions "happen at the call-site", not within the called function.
Therefore, I thought that in a call like dispatcher("one", 1) (which calls the first function with a parameter of 1) would look like: "one" gets converted to a Callable at the call-site, then a call gets made as dispatcher(Callable("one"), 1). That would mean that the constexpr constructor could be used, at least. In my experience, as long as you don't ignore the result of a constexpr call, the call is made as constexpr if it can be, else it is made as runtime. See Constexpr functions not called at compile-time if result is ignored. This isn't happening -- the conversion constructor is being called at runtime when the conversion happens within a call to my dispatch function!
Does anyone know of a way I can change my code to get the conversion constructor to be called at compile-time if it can be??? I found a totally different solution to solve this general class of problem in this post, but frankly I like the syntax of the code below better, if I could get it working.
I'm not going to include the above code in the body of this post, but rather include a more canonical example that demonstrates the behavior and also shows the behavior I saw in the post I referenced above, all-in-one.
Live demo of the below: https://onlinegdb.com/r1s1OE77v
Live demo of my "real" problem, if interested: https://onlinegdb.com/rJCQ2bGXw
First the "test fixtures":
// Modified from https://stackoverflow.com/a/40410624/12854372
// In a constexpr context, ContextIsConstexpr1(size_t) always
// simply sets _s to 1 successfully.
extern bool no_symbol_s_is_zero;
struct ContextIsConstexpr1 {
size_t _s;
constexpr ContextIsConstexpr1(size_t s) : _s(s ? 1 : no_symbol_s_is_zero) {}
};
// In a constexpr context, ContextIsConstexpr2(size_t) will cause
// a compile-time error if 0 is passed to the constructor
struct ContextIsConstexpr2 {
size_t _s;
constexpr ContextIsConstexpr2(size_t s) : _s(1) {
if(!s) {
throw logic_error("s is zero");
}
}
};
// Accept one of the above. By using a CONVERSION constructor
// and passing in a size_t parameter, it DOES make a difference.
ContextIsConstexpr1 foo(ContextIsConstexpr1 c) { return c; }
ContextIsConstexpr2 bar(ContextIsConstexpr2 c) { return c; }
Now the test code:
int main()
{
constexpr size_t CONST = 1;
#define TEST_OBVIOUS_ONES false
// ------------------------------------------------------------
// Test 1: result is compile-time, param is compile-time
// ------------------------------------------------------------
#if TEST_OBVIOUS_ONES
// Compile-time link error iif s==0 w/ any optimization (duh)
constexpr auto test1_1 = ContextIsConstexpr1(CONST);
cout << test1_1._s << endl;
// Compile-time throw iif s==0 w/ any optimization (duh)
constexpr auto test1_2 = ContextIsConstexpr2(CONST);
cout << test1_2._s << endl;
#endif
// ------------------------------------------------------------
// Test 2: result is runtime, param is compile-time
// ------------------------------------------------------------
// Compile-time link error iif s==0 w/ any optimization ***See below***
auto test2_1 = ContextIsConstexpr1(CONST);
cout << test2_1._s << endl;
// Runtime throw iif s==0 w/ any optimization
// NOTE: Throw behavior is different than extern symbol behavior!!
auto test2_2 = ContextIsConstexpr2(CONST);
cout << test2_2._s << endl;
// ------------------------------------------------------------
// Test 3: Implicit conversion
// ------------------------------------------------------------
// Compile-time link error if (1) s==0 w/ any optimization *OR* (2) s>0 w/ low optimization!!
// Note: New s>0 error due to implicit conversion ***See above***
auto test3_1 = foo(CONST);
cout << test3_1._s << endl;
// Runtime throw iif s==0 w/ any optimization
auto test3_2 = bar(CONST);
cout << test3_2._s << endl;
// ------------------------------------------------------------
// Test 4: result is ignored, param is compile-time
// ------------------------------------------------------------
// Compile-time link error w/ any 's' iif low optimization
// Note: no error w/ s==0 with high optimization, new error w/ s>0 by ignoring result ***See above***
ContextIsConstexpr1{CONST};
// Runtime throw iif s==0 w/ any optimization
ContextIsConstexpr2{CONST};
// ------------------------------------------------------------
// Get runtime input, can't optimize this for-sure
// ------------------------------------------------------------
#if TEST_OBVIOUS_ONES
size_t runtime;
cout << "Enter a value: ";
cin >> runtime;
// ------------------------------------------------------------
// Test 5: result is runtime, param is runtime
// ------------------------------------------------------------
// Compile-time link error w/ any 's' w/ any optimization (duh)
auto test5_1 = ContextIsConstexpr1(runtime);
cout << test5_1._s << endl;
// Runtime throw iif s==0 w/ any optimization (duh)
auto test5_2 = ContextIsConstexpr2(runtime);
cout << test5_2._s << endl;
// ------------------------------------------------------------
// Test 6: result is ignored, param is runtime
// ------------------------------------------------------------
// Compile-time link error w/ any 's' w/ any optimization (duh)
ContextIsConstexpr1{runtime};
// Runtime throw iif s==0 w/ any 's' w/ any optimization (duh)
ContextIsConstexpr2{runtime};
#endif
}
Does anyone know of a way I can change my code to get the conversion constructor to be called at compile-time if it can be
As I said in linked posted, call of constexpr functions at compile time is done only in constant expression.
Parameters are not constexpr.
One workaround would be to use MACRO:
#define APPLY_DISPATCHER(dispatcher, str, ...) \
do { \
constexpr callable_type_t<decltype(dispatcher), decltype(make_tuple(__VA_ARGS__))> callable(str); \
(dispatcher)(callable, __VA_ARGS__); \
} while (0)
with
template <typename Dispatcher, typename Tuple> struct callable_type;
template <typename Dispatcher, typename ... Ts>
struct callable_type<Dispatcher, std::tuple<Ts...>>
{
using type = typename Dispatcher::template Callable<Ts...>;
};
template <typename Dispatcher, typename Tuple>
using callable_type_t = typename callable_type<Dispatcher, Tuple>::type;
With usage:
APPLY_DISPATCHER(dispatcher, "one", 1);
APPLY_DISPATCHER(dispatcher, "a", 1); // Fail at compile time as expected
Demo.
But not really better than proposed dispatcher.dispatch(MAKE_CHAR_SEQ("a"), 1); (or with extension dispatcher.dispatch("a"_cs, 1);) (providing dispatch overload to be able to create constexpr Callable).

Write a function that only accepts literal `0` or literal `1` as argument

Sometimes for algebraic types it is convenient to have a constructor that takes a literal value 0 to denote the neutral element, or 1 to denote the multiplicative identity element, even if the underlying type is not an integer.
The problem is that it is not obvious how to convince the compiler only to accept, 0 or 1 without accepting any other integer.
Is there a way to do this in C++14 or beyond, for example combining literals, constexpr or static_assert?
Let me illustrate with a free function (although the idea is to use the technique for a constructor that take a single argument. Contructors cannot take template parameters either).
A function that accepts zero only could be written in this way:
constexpr void f_zero(int zero){assert(zero==0); ...}
The problem is that, this could only fail at runtime. I could write f_zero(2) or even f_zero(2.2) and the program will still compile.
The second case is easy to remove, by using enable_if for example
template<class Int, typename = std::enable_if_t<std::is_same<Int, int>{}> >
constexpr void g_zero(Int zero){assert(zero==0);}
This still has the problem that I can pass any integer (and it only fails in debug mode).
In C++ pre 11 one had the ability to do this trick to only accept a literal zero.
struct zero_tag_{};
using zero_t = zero_tag_***;
constexpr void h_zero(zero_t zero){assert(zero==nullptr);}
This actually allowed one to be 99% there, except for very ugly error messages.
Because, basically (modulo Maquevelian use), the only argument accepted would be h_zero(0).
This is situation of affairs is illustrated here https://godbolt.org/z/wSD9ri .
I saw this technique being used in the Boost.Units library.
1) Can one do better now using new features of C++?
The reason I ask is because with the literal 1 the above technique fails completely.
2) Is there an equivalent trick that can be applied to the literal 1 case? (ideally as a separate function).
I could imagine that one can invent a non-standard long long literal _c that creates an instance of std::integral_constant<int, 0> or std::integral_constant<int, 1> and then make the function take these types. However the resulting syntax will be worst for the 0 case. Perhaps there is something simpler.
f(0_c);
f(1_c);
EDIT: I should have mentioned that since f(0) and f(1) are potentially completely separate functions then ideally they should call different functions (or overloads).
In C++20 you can use the consteval keyword to force compile time evaluation. With that you could create a struct, which has a consteval constructor and use that as an argument to a function. Like this:
struct S
{
private:
int x;
public:
S() = delete;
consteval S(int _x)
: x(_x)
{
if (x != 0 && x != 1)
{
// this will trigger a compile error,
// because the allocation is never deleted
// static_assert(_x == 0 || _x == 1); didn't work...
new int{0};
}
}
int get_x() const noexcept
{
return x;
}
};
void func(S s)
{
// use s.get_x() to decide control flow
}
int main()
{
func(0); // this works
func(1); // this also works
func(2); // this is a compile error
}
Here's a godbolt example as well.
Edit:
Apperently clang 10 does not give an error as seen here, but clang (trunk) on godbolt does.
You can get this by passing the 0 or 1 as a template argument like so:
template <int value, typename = std::enable_if_t<value == 0 | value == 1>>
void f() {
// Do something with value
}
The function would then be called like: f<0>(). I don't believe the same thing can be done for constructors (because you can't explicitly set template parameters for constructors), but you could make the constructor(s) private and have static wrapper functions which can be given template parameters perform the check:
class A {
private:
A(int value) { ... }
public:
template <int value, typename = std::enable_if_t<value == 0 || value == 1>>
static A make_A() {
return A(value);
}
};
Objects of type A would be created with A::make_A<0>().
Well... you have tagged C++17, so you can use if constexpr.
So you can define a literal type when 0_x is a std::integral_constant<int, 0> value, when 1_x is a std::integral_constant<int, 1> and when 2_x (and other values) gives a compilation error.
By example
template <char ... Chs>
auto operator "" _x()
{
using t0 = std::integer_sequence<char, '0'>;
using t1 = std::integer_sequence<char, '1'>;
using tx = std::integer_sequence<char, Chs...>;
if constexpr ( std::is_same_v<t0, tx> )
return std::integral_constant<int, 0>{};
else if constexpr ( std::is_same_v<t1, tx> )
return std::integral_constant<int, 1>{};
}
int main ()
{
auto x0 = 0_x;
auto x1 = 1_x;
//auto x2 = 2_x; // compilation error
static_assert( std::is_same_v<decltype(x0),
std::integral_constant<int, 0>> );
static_assert( std::is_same_v<decltype(x1),
std::integral_constant<int, 1>> );
}
Now your f() function can be
template <int X, std::enable_if_t<(X == 0) || (X == 1), bool> = true>
void f (std::integral_constant<int, X> const &)
{
// do something with X
}
and you can call it as follows
f(0_x);
f(1_x);
For the case of Ada, you can define a subtype, a new type, or a derived type that is constrained only for the values of Integer 0 and 1.
with Ada.Text_IO; use Ada.Text_IO;
with Ada.Integer_Text_IO; use Ada.Integer_Text_IO;
procedure two_value is
-- You can use any one of the following 3 declarations. Just comment out other two.
--subtype zero_or_one is Integer range 0 .. 1; -- subtype of Integer.
--type zero_or_one is range 0 .. 1; -- new type.
type zero_or_one is new Integer range 0 .. 1; -- derived type from Integer.
function get_val (val_1 : in zero_or_one) return Integer;
function get_val (val_1 : in zero_or_one) return Integer is
begin
if (val_1 = 0) then
return 0;
else
return 1;
end if;
end get_val;
begin
Put_Line("Demonstrate the use of only two values");
Put_Line(Integer'Image(get_val(0)));
Put_Line(Integer'Image(get_val(1)));
Put_Line(Integer'Image(get_val(2)));
end two_value;
upon compiling you get the following warning message, although compiles successfully :
>gnatmake two_value.adb
gcc -c two_value.adb
two_value.adb:29:40: warning: value not in range of type "zero_or_one" defined at line 8
two_value.adb:29:40: warning: "Constraint_Error" will be raised at run time
gnatbind -x two_value.ali
gnatlink two_value.ali
And executing it gives the runtime error as specified by the compiler
>two_value.exe
Demonstrate the use of only two values
0
1
raised CONSTRAINT_ERROR : two_value.adb:29 range check failed
So, basically you can constrain the values by defining the new types, derived types or subtypes, you don't need to include the code to check the range, but based on your data type the compiler will automatically warn you.
This isn't a modern solution, but adding on to Zach Peltzer's solution, you can keep your syntax if you use macros...
template <int value, typename = std::enable_if_t<value == 0 | value == 1>>
constexpr int f_impl() {
// Do something with value
return 1;
}
#define f(x) f_impl<x>()
int main() {
f(0); //ok
f(1); //ok
f(2); //compile time error
}
Though, with the constructor problem you could just make the class templated instead of trying to have a templated constructor
template<int value, typename = std::enable_if_t<value == 0 | value == 1>>
class A {
public:
A() {
//do stuff
}
};
int main() {
A<0> a0;
auto a1 = A<1>();
// auto a2 = A<2>(); //fails!
}
The best solution to accept literal 0 that I've found to date is to use std::nullptr_t as the function's input:
struct math_object
{
real x,y,z;
math_object(std::nullptr_t) : x(0), y(0), z(0) {}
};
This has conversion advantages over some of the other solutions. For example, it allows syntax such as.. void MyFunc(const math_object &obj=0); I've been using this for years, and haven't found any trouble. However, I do not have a similar solution for literal 1. For that, I created a construct::id structure that has a global IDENTITY variable.
There's a basic problem. How can you do that in the compiler to be done for a parameter, and at the same time be efficient? Well, what do you need exactly?
That is included in strong typed languages like Pascal, or Ada. The enumerated types have only a couple of values, and the types are normally checked at development, but otherwise, the checks are eliminated by some compiler option at runtime, because just everything goes well.
A function interface is a contract. It is a contract between a seller (the writer of the function) and a buyer (the user of that function). There's even an arbiter, which is the programming language, that can act upon if someone tries to cheat the contract. But at the end, the program is being run in a machine that's open to make arbitraryness like modifying the set of enumerated values and put in the place a completely (and not permitted value).
The problem comes also with separate compilation. Separate compilation has its drawbacks, as it must face a compilation, without having to recheck and retest all previous compilations you have made. Once a compilation is finished, everything you have put in the code is there. If you want the code to be efficient, then the tests are superfluous, because caller and implementer both cope with the contract, but if you want to catch a lyer, then you have to include the test code. And then, it is better to do once for all cases, or is it better to let the programmer decide when and when not we want to catch a lyer?
The problem with C (and by legacy with C++) is that they were inspired by very good programmers, that didn't mistakes, and that have to run their software in big and slow machines. They decided to make both languages (the second was for interoperability purposes) weak typed... and so they are. Have you tried to program in Ada? or Modula-2? You'll see that, over the time, the strong typing thing is more academic than otherwise, and finally what you want, as a professional, is to have the freedom to say: now I want to be safe (and include test code), and now I know what I'm doing (and please be most efficient as you can)
Conclusion
The conclussion is that you are free to select the language, to select the compiler, and to relax the rules. The compilers have the possibility to allow you that. And you have to cope with it, or invent (this is something that todays happens almost each week) your own programming language.
This is the answer to my question, based on #IlCapitano answer for a wrapper class.
This wrapper class can be made private an used only on the construction.
class Matrix {
struct ZeroOROne {
/*implicit*/ consteval ZeroOROne(int n) : val_{n} {
if (n != 0 and n != 1) {throw;} // throw can produce an error at compile time
}
int val_;
};
public:
constexpr Matrix(ZeroOROne _0_or_1) {
if(_0_or_1.val_ == 0) { // this cannot be if constexpr, but that is ok
a00 = a01 = a10 = a11 = 0.0;
new int{0}; // allocation could is ok here
} else {
a00 = a11 = 1.0;
a10 = a01 = 0.0;
new int{0}; // allocation could is ok here
}
}
double a00; double a01;
double a10; double a11;
};
In this way, only Matrix A(0) or Matrix A(1) are allowed.
(Although it works with constant variables as well, but that is ok.)
int main() {
// ZeroOROne(0);
// ZeroOROne(1);
// ZeroOROne(2); // compilation error
Matrix A(0);
Matrix B(1);
// Matrix C(2); // compilation error
int const d = 0; // this works because the compiler can "see" the 0.
Matrix D(d);
constexpr int e = 0;
Matrix E(e);
// int f = 0;
// Matrix F(f); // compile error
return B.a00;
}
Here it is shown that the "runtime" if in the constructor is not a problem and can be elided by the compiler: https://godbolt.org/z/hd6TWY6qW
The solution needs C++20 and it works in recent version of GCC and clang.

Enforcing function contract at compile time when possible

(this question was inspired by How can I generate a compilation error to prevent certain VALUE (not type) to go into the function?)
Let's say, we have a single-argument foo, semantically defined as
int foo(int arg) {
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
The whole code above is used to illustrate a simple idea - function returns it's own argument unless the argument is equal to 5, in which case behavior is undefined.
Now, the challenge - modify the function in such a way, that if it's argument is known at compile time, a compiler diagnostic (warning or error) should be generated, and if not, behavior remains undefined in runtime. Solution could be compiler-dependent, as long as it is available in either one of the big 4 compilers.
Here are some potential routes which do not solve the problem:
Making function a template which takes it's argument as a template parameter - this doesn't solve the problem because it makes function ineligible for run-time arguments
Making function a constexpr - this doesn't solve the problem, because even when compilers see undefined behavior, they do not produce diagnostics in my tests - instead, gcc inserts ud2 instruction, which is not what I want.
I got error with constexpr when used in constant expression for:
constexpr int foo(int arg) {
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
Demo
We cannot know that argument value is known at compile type, but we can use type representing value with std::integral_constant
// alias to shorten name.
template <int N>
using int_c = std::integral_constant<int, N>;
Possibly with UDL with operator "" _c to have 5_c, 42_c.
and then, add overload with that:
template <int N>
constexpr auto foo(int_c<N>) {
return int_c<foo(N)>{};
}
So:
foo(int_c<42>{}); // OK
foo(int_c<5>{}); // Fail to compile
// and with previous constexpr:
foo(5); // Runtime error, No compile time diagnostic
constexpr auto r = foo(5); // Fail to compile
As I said, arguments are not known to be constant inside the function, and is_constexpr seems not possible in standard to allow dispatch, but some compiler provide built-in for that (__builtin_constant_p), so with MACRO, we can do the dispatch:
#define FOO(X) [&](){ \
if constexpr (__builtin_constant_p(X)) {\
return foo(int_c<__builtin_constant_p (X) ? X : 0>{});\
} else {\
return foo(X); \
} \
}()
Demo
Note: Cannot use foo(int_c<X>{}) directly, even in if constexpr, as there is still some syntax check.
gcc/clang/intel compilers support __builtin_constant_p, so you can use something like that:
template <int D>
int foo_ub(int arg) {
static_assert(D != 5, "error");
int* parg = nullptr;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
#define foo(e) foo_ub< __builtin_constant_p(e) ? e : 0 >(e)
these statements produce compile time error:
foo(5)
foo(2+3)
constexpr int i = 5; foo(i);
while all others - runtime segfault (or ub if no nullptr is used)
It's not perfect and it requires us to use arguments in two different places, but it 'works':
template<int N = 0>
int foo(int arg = 0) {
static_assert(N != 5, "N cannot be 5!");
int* parg;
if (arg != 5) {
parg = &arg;
}
return *parg;
}
We can call it like so:
foo<5>(); // does not compile
foo(5); // UB
foo<5>(5); // does not compile
foo<5>(10); // does not compile
foo<10>(5); // UB
foo(); // fine
foo<10>(); // fine
foo(10); // fine

Integral template parameter. error: use of 'this' in a constant expression

I tried to find a similar answered question in SO but without success.
Question is why it is considered as error to use at compile time known at compile time value of template parameter of known at compile time type? Common sense tells me, that this code can be OK. What is wrong in this case?
Thanks!
#include <array>
using Cont = std::array<int, 2>;
class A
{
Cont a_ = {};
public:
int& at(bool first)
{
static_assert(sizeof(a_) / sizeof(int) == 2); // OK
static_assert(a_.size() > 1); // error: non-constant condition for static assertion. error: use of 'this' in a constant expression
return a_[first ? 0 : 1];
}
};
at compiler explorer
UPDATE: it looks like dublicate but may be not because in the question under link the speech is about run-time evaluation, but here looks like a_.size() can be evaluated in compile-time.
UPDATE2 More clear example (after considering answers and comments)
#include <array>
using Cont = std::array<int, 2>;
// OK
void checkSize(const Cont& b)
{
static_assert(b.size() == 2);
}
class A
{
Cont a_ = {};
public:
constexpr void checkSize() const
{
Cont b = {};
static_assert(b.size() == 2); // OK
static_assert(sizeof(a_) / sizeof(int) == 2); // OK
static_assert(a_.size() == 2); // error: non-constant condition for static assertion. error: use of 'this' in a constant expression
}
};
shows that the problem in this is involved to evaluate a_.size(). But why it is needed there, while a_ is known by compiler as non-virtual type and size() can be evaluated in compile time, may be is another question, so I'll check first answer.
std::array::size, even though a constexpr function, isn't a static function. This means it requires an object instance to be invoked.
In this particular case, at isn't constexpr†, therefore this isn't either and in turn _a. Since _a isn't constexpr, the result of _a.size() isn't constexpr too.
† Even if it is, the body still isn't considered constexpr.
a_ is a member of the class A.
a_.size() is a simplification of this->a_.size() because size is not a static function, which means that in order to access a_, you have to access this.
this is a pointer to a class A and is NOT a compile time constant making your static_assert fail.
Using template is probably easier :
template<int N>
class B {
std::array<int, N> a_;
public:
int& at(bool first)
{
static_assert((sizeof(a_) / sizeof(int)) == 2, "Sizeof operator"); // OK
static_assert(N > 1, "Size method"); // No problem here
return a_[first ? 0 : 1];
}
};