I want to use helpful comments behind constraints so users can find them in the case of compilation errors. This works well with functions and classes, except for the below case of a constructor.
#include <iostream>
template<int n_>
struct A{
static constexpr int n = n_;
};
template<int n>
struct B{
template<typename T>
requires(T::n==n) // HELPFUL COMMENT
B(T t){
static_assert(T::n==n); // suppose this crashes uninsightfully
}
};
int main() {
B<2> b = A<1>{};
// here I WANT the error message "error: constraint violated: requires(A::n==n) // HELPFUL COMMENT [notice: reduces to 1==2]"
return 0;
}
What is the reason for this. Can the usual error message behavior as commented be restored by means of a different implementation approach?
Remark: I need elision, references, and const properties; hence it would be very undesirable if the function could not be a constructor.
Issue with Static_Assert
When using static_assert, the compiler won't stop at trying to compile a piece of code that it is not supposed to use. Worse, however, the compiler burries the useful static assertion failure message below litter of (in practice incomprehensible) errors which stem from the mere fact of the violated constraint. The below example shows this:
template<int m, int n> struct Aux{};
struct Foo{
template<int m, int n>
Foo(Aux<m,n>){
static_assert(m==n); // HINT: B HAS WRONG DIMENSION
}
};
template<typename T, int n>
struct Data{
T x[n];
};
struct A{
static constexpr int n = 1;
template<typename T>
static constexpr Data<T,n> get_data(){
return Data<T,n>{{1}};
}
};
template<typename Tfloat, int n>
struct B{
Foo foo;
Data<Tfloat,n> data;
template<typename T>
B(T):foo(Aux<T::n,n>{}),data(T::template get_data<Tfloat>()) {}
};
int main() {
B<double,2> b = A{};
// here I WANT the error message "error: constraint violated: requires(A::n==n) // HELPFUL COMMENT [notice: reduces to 1==2]"
return 0;
}
Error Message Gcc 13.2.0 :
~: In instantiation of 'B<Tfloat, n>::B(T) [with T = A; Tfloat = double; int n = 2]':
~:36:23: required from here
~:31:62: error: array must be initialized with a brace-enclosed initializer
31 | B(T):foo(Aux<T::n,n>{}),data(T::template get_data<Tfloat>()) {}
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~
~: In instantiation of 'Foo::Foo(Aux<m, n>) [with int m = 1; int n = 2]':
~:31:10: required from 'B<Tfloat, n>::B(T) [with T = A; Tfloat = double; int n = 2]'
~:36:23: required from here
~:8:24: error: static assertion failed
8 | static_assert(m==n); // HINT: B HAS WRONG DIMENSION
| ~^~~
~:8:24: note: the comparison reduces to '(1 == 2)'