Hi everyone,
I wrote some code that compiles, and I don't know why. Here is a minimal example:
#include <vector>
template <typename T>
concept IsIncrementable = requires(T a) { // Dummy concept for the example
++a;
};
template<typename T>
struct Test
{
static constexpr int a = [](auto x) -> int requires IsIncrementable<T> { return 0; }(0);
};
int main()
{
// T = std::vector<int>
// It does not satisfy IsIncrementable<T>
// Why does this code compiles ?
Test<std::vector<int>> t;
return 0;
}
Essentially, a variable is initialized through IIFE. Here are some indication about this code:
template <IsIncrementable T> struct Test {};
instead or with requires. I know. And in the full example, I can not do such things...I thought the code might prevent Test to be instantiated with non-incrementable types. It turns out that I can do:
Test<std::vector<int>> t;
And I can use the a class, until I directly use the member variable, ie I use t.a
or Test<std::vector<int>>::a
.
Thank you in advance.
decltype(x)
does not change the behavior.Test<std::vector<int>>
What DOES change the behavior however, is if I use auto instead:
static constexpr auto a = ...
makes it impossible to instantiate Test<std::vector<int>>
, which is, at least to me, the expected behavior.
Static data members are instantiated independently of the rest of the class. Your program isn't using Test<T>::a
anywhere, so it's simply not instantiated. If you did this:
int main()
{
return Test<std::vector<int>>::a;
}
then you'd get the error that you expected.
Additionally, when you did this:
What DOES change the behavior however, is if I use
auto
instead:static constexpr auto a = ...
Now analyzing a
requires evaluating the expression to determine its type, which leads to earlier instantiation. That just wasn't necessary when you explicitly specified int
, so it didn't happen yet.