Template function/class implicit instantiation rules used in stateful meta programming - c++

I am working with a code example concerning stateful meta programming.
The original code example can be found from this link: http://b.atch.se/posts/non-constant-constant-expressions/#appendix-clang-workaround
In order to understand this technique, I try to modify the code example each time a bit. Here follows the latest version which still works:
constexpr int adl_flag(int);
template <class Tag> struct writer {
friend constexpr int adl_flag(int) {
return 0;
}
};
template <int = adl_flag(0)> constexpr bool is_flag_usable(int) {
return true;
}
constexpr bool is_flag_usable (...) {
return false;
}
template <
class Tag = int,
bool B = is_flag_usable(0),
int = sizeof (writer<Tag>) // replace Tag with int
>
constexpr int f() {
return B;
}
int main() {
constexpr int a = f();
constexpr int b = f();
static_assert(a != b, "fail");
return 0;
}
To me, it seems trivial to replace Tag with int. But this replacement in fact make the static_assert fail.
I guess this is because the compiler no longer implicitly instantiate f for the second call :
constexpr int b = f();
But the template type parameter Tag seems has nothing to do with this. Can somebody explain what's actually going on here, please.
The compiler I used is g++ 5.4.1. Compiling with -std=gnu++14.

sizeof(writer<int>) is non-dependent. That means that wrapper<int> is found in first phase lookup, when f is parsed (once).
sizeof(writer<Tag>), on the other hand, is dependent on Tag. Thus, its lookup is deferred until phase two, when f is instantiated (at each of its call sites).

Related

Class non-type template parameter partial specialization

I was playing around with some c++20 features using gcc 9.0.1. It seems like there is support for class non-type template parameters. But I run into a problem that template partial specialization isn't used when selecting the template.
Following example is a test case which I came up after figuring out the root cause in my more complex code.
// g++ -std=c++2a -c test.cc -o test.o
#include <type_traits>
template<typename T>
struct Integer {
constexpr Integer() : val{} {}
constexpr Integer(T v) : val{v} {}
constexpr bool operator<(Integer o) const { return val < o.val; }
template<typename O, typename = std::enable_if_t<std::is_integral_v<O>>>
constexpr bool operator<(O o) const { return val < o; }
constexpr bool operator==(Integer o) const { return val == o.val; }
private:
T val;
};
template<auto val, typename = void>
struct test {
static constexpr bool is_specialized = false;
static constexpr auto value = val;
};
template<auto val>
struct test<val, std::enable_if_t<val < 64>> {
static constexpr bool is_specialized = true;
static constexpr auto value = val;
};
constexpr int i5 = 5;
constexpr int i70 = 70;
constexpr unsigned long s5 = 5;
constexpr unsigned long s70 = 70;
using IT = Integer<int>;
constexpr Integer<int> o5 = 5;
constexpr Integer<int> o70 = 70;
static_assert(std::is_same_v<decltype(test<i5>::value),decltype(i5)>);
static_assert(test<i5>::value == i5);
static_assert(test<i5>::is_specialized);
static_assert(std::is_same_v<decltype(test<i70>::value),decltype(i70)>);
static_assert(test<i70>::value == i70);
static_assert(!test<i70>::is_specialized);
static_assert(std::is_same_v<decltype(test<s5>::value),decltype(s5)>);
static_assert(test<s5>::value == s5);
static_assert(test<s5>::is_specialized);
static_assert(std::is_same_v<decltype(test<s70>::value),decltype(s70)>);
static_assert(test<s70>::value == s70);
static_assert(!test<s70>::is_specialized);
static_assert(std::is_same_v<decltype(test<o5>::value),decltype(o5)>);
static_assert(test<o5>::value == o5);
// GCC 9.0.1: error: static assertion failed
// This basically mean object template parameters work but specialization isn't
// used like I would expect.
static_assert(test<o5>::is_specialized);
static_assert(std::is_same_v<decltype(test<o70>::value),decltype(o70)>);
static_assert(test<o70>::value == o70);
static_assert(!test<o70>::is_specialized);
I tried to find online anything which would indicate if my expectations are correct or not. To me it seems like at least without specialization class non-type parameter works the way I would expect but specialization isn't selected.
One suspect is missing support for three-way comparison (operator<=>). Proposal seems to require defaulted operator. As operator support is missing it might make the class non-type template parameter support only partial even tough status page claims support.
I couldn't test this with clang as my latest version doesn't yet support this feature. I don't know if latest sources already implement support.
Is this just a bug in the preliminary implementation?
Is there a rule preventing this case from working?
Is there a simple modification which would make the code to select specialization like I expect?
Relevant standard paper: Class Types in Non-Type Template Parameters

Perfect forwarding return type of a template class member function

Consider this code:
int TEN = 10;
template < typename >
struct XX
{
//static auto&& ban(auto&&...) // FAILS!?
template < typename... Args > static auto&& ban(Args&&...)
{ return TEN; }
};
int main()
{
XX<void>::ban();
return 0;
}
The declaration of ban(auto&&...) fails with
error: invalid initialization of reference of type 'auto&&' from expression of type 'int'
when compiling with gcc-8.3 -std=c++17 -fconcepts.
So, is this a bug in the implementation of GCC?
Note that it passes when class XX is not a template.
Indeed it look like a compiler bug.
A simple workaround would be to use trailing return type:
static auto ban(auto&&...) -> auto&& // strangely work
{ return TEN; }
Also, note that this syntax is not yet fully supported by GCC. The concept terse template syntax should allow this:
template<typename>
concept /* bool */ test = true;
auto func(test auto) -> void {}
And don't quite work yet with GCC concepts implementation.

Why does removing the default parameter break this constexpr counter?

Consider the following code that implements a compile time counter.
#include <iostream>
template<int>
struct Flag { friend constexpr int flag(Flag); };
template<int N>
struct Writer
{
friend constexpr int flag(Flag<N>) { return 0; }
};
template<int N>
constexpr int reader(float, Flag<N>) { return N; }
template<int N, int = flag(Flag<N>{})>
constexpr int reader(int, Flag<N>, int value = reader(0, Flag<N + 1>{}))
{
return value;
}
template<int N = reader(0, Flag<0>{}), int = sizeof(Writer<N>) >
constexpr int next() { return N; }
int main() {
constexpr int a = next();
constexpr int b = next();
constexpr int c = next();
constexpr int d = next();
std::cout << a << b << c << d << '\n'; // 0123
}
For the second reader overload, if I put the default parameter inside the body of the function, like so:
template<int N, int = flag(Flag<N>{})>
constexpr int reader(int, Flag<N>)
{
return reader(0, Flag<N + 1>{});
}
Then the output will become:
0111
Why does this happen? What makes the second version not work anymore?
If it matters, I'm using Visual Studio 2015.2.
Without value being passed as a parameter, nothing stops the compiler from caching the call to reader(0, Flag<1>).
In both cases first next() call will work as expected since it will immediately result in SFINAEing to reader(float, Flag<0>).
The second next() will evaluate reader<0,0>(int, ...), which depends on reader<1>(float, ...) that can be cached if it does not depend on a value parameter.
Unfortunately (and ironically) the best source I found that confirms that constexpr calls can be cached is #MSalters comment to this question.
To check if your particular compiler caches/memoizes, consider calling
constexpr int next_c() { return next(); }
instead of next(). In my case (VS2017) the output turns into 0000.
next() is protected from caching by the fact that its default template arguments actually change with every instantiation, so it's a new separate function every time. next_c() is not a template at all, so it can be cached, and so is reader<1>(float, ...).
I do believe that this is not a bug and compiler can legitimately expect constexprs in compile-time context to be pure functions.
Instead it is this code that should be considered ill-formed - and it soon will be, as others noted.
The relevance of value is that it participates in overload resolution. Under SFINAE rules, template instantiation errors silently exclude candidates from overload resolution. But it does instantiate Flag<N+1>, which causes the overload resolution to become viable the next time (!). So in effect you're counting successful instantiations.
Why does your version behave differently? You still reference Flag<N+1>, but in the implementation of the function. This is important. With function templates, the declaration must be considered for SFINAE, but only the chosen overload is then instantiated. Your declaration is just template<int N, int = flag(Flag<N>{})> constexpr int reader(int, Flag<N>); and does not depend on Flag<N+1>.
As noted in the comments, don't count on this counter ;)

Code executable in compile time and runtime [duplicate]

Lets say that you have a function which generates some security token for your application, such as some hash salt, or maybe a symetric or asymetric key.
Now lets say that you have this function in your C++ as a constexpr and that you generate keys for your build based on some information (like, the build number, a timestamp, something else).
You being a diligent programmer make sure and call this in the appropriate ways to ensure it's only called at compile time, and thus the dead stripper removes the code from the final executable.
However, you can't ever be sure that someone else isn't going to call it in an unsafe way, or that maybe the compiler won't strip the function out, and then your security token algorithm will become public knowledge, making it more easy for would be attackers to guess future tokens.
Or, security aside, let's say the function takes a long time to execute and you want to make sure it never happens during runtime and causes a bad user experience for your end users.
Are there any ways to ensure that a constexpr function can never be called at runtime? Or alternately, throwing an assert or similar at runtime would be ok, but not as ideal obviously as a compile error would be.
I've heard that there is some way involving throwing an exception type that doesn't exist, so that if the constexpr function is not deadstripped out, you'll get a linker error, but have heard that this only works on some compilers.
Distantly related question: Force constexpr to be evaluated at compile time
In C++20 you can just replace constexpr by consteval to enforce a function to be always evaluated at compile time.
Example:
int rt_function(int v){ return v; }
constexpr int rt_ct_function(int v){ return v; }
consteval int ct_function(int v){ return v; }
int main(){
constexpr int ct_value = 1; // compile value
int rt_value = 2; // runtime value
int a = rt_function(ct_value);
int b = rt_ct_function(ct_value);
int c = ct_function(ct_value);
int d = rt_function(rt_value);
int e = rt_ct_function(rt_value);
int f = ct_function(rt_value); // ERROR: runtime value
constexpr int g = rt_function(ct_value); // ERROR: runtime function
constexpr int h = rt_ct_function(ct_value);
constexpr int i = ct_function(ct_value);
}
Pre C++20 workaround
You can enforce the use of it in a constant expression:
#include<utility>
template<typename T, T V>
constexpr auto ct() { return V; }
template<typename T>
constexpr auto func() {
return ct<decltype(std::declval<T>().value()), T{}.value()>();
}
template<typename T>
struct S {
constexpr S() {}
constexpr T value() { return T{}; }
};
template<typename T>
struct U {
U() {}
T value() { return T{}; }
};
int main() {
func<S<int>>();
// won't work
//func<U<int>>();
}
By using the result of the function as a template argument, you got an error if it can't be solved at compile-time.
A theoretical solution (as templates should be Turing complete) - don't use constexpr functions and fall back onto the good-old std=c++0x style of computing using exclusively struct template with values. For example, don't do
constexpr uintmax_t fact(uint n) {
return n>1 ? n*fact(n-1) : (n==1 ? 1 : 0);
}
but
template <uint N> struct fact {
uintmax_t value=N*fact<N-1>::value;
}
template <> struct fact<1>
uintmax_t value=1;
}
template <> struct fact<0>
uintmax_t value=0;
}
The struct approach is guaranteed to be evaluated exclusively at compile time.
The fact the guys at boost managed to do a compile time parser is a strong signal that, albeit tedious, this approach should be feasible - it's a one-off cost, maybe one can consider it an investment.
For example:
to power struct:
// ***Warning: note the unusual order of (power, base) for the parameters
// *** due to the default val for the base
template <unsigned long exponent, std::uintmax_t base=10>
struct pow_struct
{
private:
static constexpr uintmax_t at_half_pow=pow_struct<exponent / 2, base>::value;
public:
static constexpr uintmax_t value=
at_half_pow*at_half_pow*(exponent % 2 ? base : 1)
;
};
// not necessary, but will cut the recursion one step
template <std::uintmax_t base>
struct pow_struct<1, base>
{
static constexpr uintmax_t value=base;
};
template <std::uintmax_t base>
struct pow_struct<0,base>
{
static constexpr uintmax_t value=1;
};
The build token
template <uint vmajor, uint vminor, uint build>
struct build_token {
constexpr uintmax_t value=
vmajor*pow_struct<9>::value
+ vminor*pow_struct<6>::value
+ build_number
;
}
In the upcoming C++20 there will be consteval specifier.
consteval - specifies that a function is an immediate function, that is, every call to the function must produce a compile-time constant
Since now we have C++17, there is an easier solution:
template <auto V>
struct constant {
constexpr static decltype(V) value = V;
};
The key is that non-type arguments can be declared as auto. If you are using standards before C++17 you may have to use std::integral_constant. There is also a proposal about the constant helper class.
An example:
template <auto V>
struct constant {
constexpr static decltype(V) value = V;
};
constexpr uint64_t factorial(int n) {
if (n <= 0) {
return 1;
}
return n * factorial(n - 1);
}
int main() {
std::cout << "20! = " << constant<factorial(20)>::value << std::endl;
return 0;
}
Have your function take template parameters instead of arguments and implement your logic in a lambda.
#include <iostream>
template< uint64_t N >
constexpr uint64_t factorial() {
// note that we need to pass the lambda to itself to make the recursive call
auto f = []( uint64_t n, auto& f ) -> uint64_t {
if ( n < 2 ) return 1;
return n * f( n - 1, f );
};
return f( N, f );
}
using namespace std;
int main() {
cout << factorial<5>() << std::endl;
}

Getting return type of an overloaded member function

I am trying to determine the return type of an overloaded member function to later use that type in my function template (see the example below). Cannot figure out how to do it using C++11 templating machinery (without modifying the definitions for struct A and B in the code below). Is this doable (in C++11 in general and MSVS2013 in particular) and how?
struct A{};
struct B{};
struct X
{
double f(A&);
int* f(B&);
};
template<typename T, typename R = /*??? what X::f(T) returns ???*/>
R ff(T& arg)
{
X x;
R r = x.f(arg); // preferably if I can create local variables of type R here
return r;
}
int main()
{
A a; ff(a);
B b; ff(b);
}
You can use decltype() for this, using std::declval to simulate values of the types needed to create the method call expression:
typename R = decltype(std::declval<X>().f(std::declval<T&>()))
Here is a demo that outputs the type ID of R; you can see that it correctly deduces double and int * for ff(a) and ff(b) respectively.
Side note: the entire body of your template function can be reduced to return X().f(arg);.
You can also use C++14 auto return type deduction like this:
template<typename T>
auto ff(T& arg)
{
X x;
auto r = x.f(arg);
return r;
}
In C++11, you can use the late return type:
template <typename T>
auto ff(T&& arg) -> decltype(std::declval<X>().f(arg))
{
return X().f(arg);
}
In C++14, you can even omit the late return type and let the compiler determine everything itself, like in Baum mit Augen's answer.
Edit: made the late return type work for non-default constructable types X.