Template Type != Deduced type - c++

I'm attempting to give a friendly name to a type as a template typename because I need to use the name in a few places within the function. The type is being deduced based on the number of other template arguments in the parameter pack, as shown below:
#include <cassert>
#include <functional>
#include <type_traits>
template < typename ... TArgs, typename Functor = std::function< std::conditional_t< sizeof...(TArgs) == 0, int (), int (TArgs...) > > >
void DoStuff(const Functor & func, TArgs ... args) {
if constexpr (sizeof...(TArgs) == 0)
assert(typeid(Functor).hash_code() == typeid(std::function<int ()>).hash_code());
else
assert(typeid(Functor).hash_code() == typeid(std::function<int (TArgs...)>).hash_code());
}
int main(int argc, char * argv[]) {
DoStuff([] () { return 5; });
DoStuff([] (int a) { return a; });
return 0;
}
This compiles just fine, but both assertions fail because the alias Functor is not actually a std::function<>. On the other hand, if I change the code to repeat the definition of Functor in the typeid calls it works perfectly, like below:
#include <cassert>
#include <functional>
#include <type_traits>
template < typename ... TArgs, typename Functor = std::function< std::conditional_t< sizeof...(TArgs) == 0, int (), int (TArgs...) > > >
void DoStuff(const Functor & func, TArgs ... args) {
if constexpr (sizeof...(TArgs) == 0)
assert(typeid(std::function< std::conditional_t< sizeof...(TArgs) == 0, int (), int (TArgs...) > >).hash_code() == typeid(std::function<int ()>).hash_code());
else
assert(typeid(std::function< std::conditional_t< sizeof...(TArgs) == 0, int (), int (TArgs...) > >).hash_code() == typeid(std::function<int (TArgs...)>).hash_code());
}
int main(int argc, char * argv[]) {
DoStuff([] () { return 5; });
DoStuff([] (int a) { return a; });
return 0;
}
Why is the first declaration (using the typname Functor = ...) incorrect? Is there a different way to make that alias? Note that in answering the second question, it is OK if the solution is a const expression, the examples are only not constexpr because of the use of typeid.

Why is the first declaration (using the typename Functor = ...) incorrect?
You're providing a default type for the template parameter Functor. But the default type is only used if the type is not otherwise specified or deduced. In this case, template deduction will deduce Functor in both cases to be whatever the unique type of the lambda is that it is invoked with (while Args... deduces as an empty pack).
This is similar to default function arguments not being used when they are provided.
I'm not sure what your assert()s are supposed to accomplish, but if you're checking types you should use static_assert.

Related

Can I change the template argument deduction order for a generic variadic lambda?

Take the following code, which is a simplified example:
template <typename F>
void foo(F f) {
//bool some = is_variadic_v<F>; // Scenario #1
bool some = true; // Scenario #2
f(int(some), int(some));
}
int main() {
auto some = [](int i, int j) {
std::cout << i << " " << j << '\n';
};
foo([&some](auto... params) {
some(params...);
});
}
A function takes a generic variadic lambda and calls it with a fixed set of arguments. This lambda itself then just calls another function/lambda with a matching prototype.
As one could expect, in scenario 2, when f is called inside foo, the compiler will deduce params... to be the parameter pack {1, 1}.
For scenario #1, I am using a code from another Q&A to deduce the arity of a callable object. If however such an object is callable with more than a pre-defined maximum amount of arguments, it is considered "variadic". In detail, is_variadic_v will employ a form of expression SFINAE where it is attempted to call the function object with a decreasing number of arguments having an "arbitrary type" that is implictly convertible to anything.
The problem is now that apparently, the compiler will deduce F (and along its argument pack) during this metacode, and if it is variadic (such as in this case), it deduces F as a lambda taking the dummy arguments, i.e. something like main()::lambda(<arbitrary_type<0>, arbitrary_type<1>, arbitrary_type<2>, ..., arbitrary_type<N>>) if N is the "variadic limit" from above. Now params... is deduced as arbitrary_type<1>, arbitrary_type<2>, ... and correspondingly, the call some(params...) will fail.
This behaviour can be demonstrated in this little code example:
#include <utility>
#include <type_traits>
#include <iostream>
constexpr int max_arity = 12; // if a function takes more arguments than that, it will be considered variadic
struct variadic_type { };
// it is templated, to be able to create a
// "sequence" of arbitrary_t's of given size and
// hence, to 'simulate' an arbitrary function signature.
template <auto>
struct arbitrary_type {
// this type casts implicitly to anything,
// thus, it can represent an arbitrary type.
template <typename T>
operator T&&();
template <typename T>
operator T&();
};
template <
typename F, auto ...Ints,
typename = decltype(std::declval<F>()(arbitrary_type<Ints>{ }...))
>
constexpr auto test_signature(std::index_sequence<Ints...> s) {
return std::integral_constant<int, size(s)>{ };
}
template <auto I, typename F>
constexpr auto arity_impl(int) -> decltype(test_signature<F>(std::make_index_sequence<I>{ })) {
return { };
}
template <auto I, typename F, typename = std::enable_if_t<(I > 0)>>
constexpr auto arity_impl(...) {
// try the int overload which will only work,
// if F takes I-1 arguments. Otherwise this
// overload will be selected and we'll try it
// with one element less.
return arity_impl<I - 1, F>(0);
}
template <typename F, auto MaxArity>
constexpr auto arity_impl() {
// start checking function signatures with max_arity + 1 elements
constexpr auto tmp = arity_impl<MaxArity+1, F>(0);
if constexpr (tmp == MaxArity+1)
return variadic_type{ }; // if that works, F is considered variadic
else return tmp; // if not, tmp will be the correct arity of F
}
template <typename F, auto MaxArity = max_arity>
constexpr auto arity(F&&) { return arity_impl<std::decay_t<F>, MaxArity>(); }
template <typename F, auto MaxArity = max_arity>
constexpr auto arity_v = arity_impl<std::decay_t<F>, MaxArity>();
template <typename F, auto MaxArity = max_arity>
constexpr bool is_variadic_v = std::is_same_v<std::decay_t<decltype(arity_v<F, MaxArity>)>, variadic_type>;
template <typename F>
void foo(F f) {
bool some = is_variadic_v<F>;
//bool some = true;
f(int(some), int(some));
}
int main() {
auto some = [](int i, int j) {
std::cout << i << " " << j << '\n';
};
foo([&some](auto... params) {
some(params...);
});
}
Can I prevent this behaviour? Can I force the compiler to re-deduce the parameter list?
EDIT:
An additional peculiarity is that the compiler seems to act kind of schizophrenic. When I change the contents of foo to
foo([&some](auto... params) {
// int foo = std::index_sequence<sizeof...(params)>{ };
std::cout << sizeof...(params) << '\n';
});
the compiler will create a program that will print 2 in this example. If however I include the commented line (which, as it makes no sense, should trigger a compiler diagnostic), I get confronted with
error: cannot convert 'std::index_sequence<13>' {aka 'std::integer_sequence<long unsigned int, 13>'} to 'int' in initialization
85 | int foo = std::index_sequence<sizeof...(params)>{ };
so does the compiler now deduces sizeof...(params) to be 2 and 13 at the same time? Or did he change his mind and chooses now 13 just because I added another statement into the lambda? Compilation will also fail if I instead choose a static_assert(2 == sizeof...(params));. So the compiler deduces sizeof...(params) == 2, except if I ask him whether he did deduce 2, because then he didn't.
Apparently, it is very decisive for the parameter pack deduction what is written inside the lambda. Is it just me or does this behaviour really look pathologic?

static_assert each parameter's size in parameter pack

I am trying to check whether each parameter within a parameter pack can be stored within 8 bytes (sizeof <= 8)
I have the function signature:
template <typename Return, typename... Arguments>
inline auto invoke(std::uint64_t hash, Arguments... arguments) -> Return
Using fold expressions, I have tried:
static_assert((sizeof(arguments) <= 8 && ...));
Which failed to compile with unexpected token '...', expected 'expression' - I assume it's invalid or incorrect?
Using C++20 concepts and constraints, I assume something along the lines of is possible?
template <typename Return, typename... Arguments> requires (sizeof(arguments) <= 8 || ...)
inline auto invoke(std::uint64_t hash, Arguments... arguments) -> Return
I assume there is a way of using the standard library to say check that a type fits within a std::uint64_t say also?
With C++20 concepts, there are many ways how to achieve the desired behavior. For instance:
template <typename T, size_t N>
concept bool SizeLessEqual = sizeof(T) <= N;
template <SizeLessEqual<8>... Types>
void f() { }
int main() {
f<bool, char, int, double>();
f<std::string>(); // error
}
Live demo: https://wandbox.org/permlink/Q9tifNVplsx9BjGN
Another option is your solution:
template <typename... Types> requires ((sizeof(Types) <= 8) && ...)
void f() { }
Or, e.g.:
template <typename... Types> requires (std::max({ sizeof(Types)... }) <= 8)
void f() { }
Try this way:
#include <cstdint>
#include <utility>
template <typename... Arguments>
auto invoke(std::uint64_t hash, Arguments... arguments)
{
auto check = []( auto&& argument )
{
static_assert( sizeof(argument) <= 8, "size too large" );
return 0;
};
auto dummy = { 0, ( check(std::forward<Arguments>(arguments)), 0) ... };
return 0;
}
int main()
{
invoke( 0UL, '1' );
invoke( 0UL, '1', 2 );
invoke( 0UL, '1', 2, 3UL );
//invoke( 0UL, '1', 2, 3UL, static_cast<long double>(1.0) );
return 0;
}
Using the comma operator and the initializer_list to do the trick.
With C++17, we can further trim the code to:
template <typename... Arguments>
auto invoke(std::uint64_t hash, Arguments... arguments)
{
auto check = []( auto&& argument )
{
static_assert( sizeof(argument) <= 8, "size too large" );
};
(check(std::forward<Arguments>(arguments)), ...);
}
taking the advantage of fold expressions.
I do not understand the downvotes, but as this is my last post in stackoverflow, I uploaded a live example at wandbox: https://wandbox.org/permlink/NZbqpRaTs2TFOCwG

Binding to a variadic member function

So here is the situation: I have two classes with static inheritance through CRTP. The base class has a run method that calls the derived method with a variadic template so that the arguments are flexible. Now the derived class contains a function object. The derived class has the implementation that is called by the base class. It may seem unnecessary but in the full version of this code more commands than just the contained function are run. Next there is a method that converts the function to a bool(void) function by binding all the variadic arguments, and instance to the the method CrtpBase::Run. This is where I am having an issue. I have tried two different approached, the version using a lambda is commented out. Neither method works. My goal is to have VoidFunction bind all the parameters so that I can execute the function at my leisure without the arguments. What am I doing wrong here?
#include <functional>
#include <utility>
template <typename D>
struct CrtpBase {
template <typename ... Args>
bool Run(Args&& ... args) const {
return static_cast<D&>(*this).Impl(std::forward<Args>(args) ...);
}
};
template <typename ... Args>
struct CrtpDerived : public CrtpBase<CrtpDerived<Args ...>> {
CrtpDerived(std::function<bool(Args ...)> function) : runable(std::move(function)) {}
bool Impl(Args&& ... args) const {
return this->runable(std::forward<Args>(args) ...);
}
std::function<bool(Args ...)> runable;
};
template <typename D, typename ... Args>
std::function<bool()> VoidFunction(CrtpBase<D> base, Args&& ... args) {
// return [&base, &args ...]()->bool{return CrtpBase<D>::template Run<Args ...>(base);};
return std::bind(CrtpBase<D>::template Run<Args ...>, base, std::forward<Args>(args) ...);
}
int main(int argc, char** argv) {
std::function<bool(int&)> fn = [](int& a)->bool{a /= 2; return (a % 2) == 1;};
CrtpDerived<int&> derived(fn);
int x = 7;
auto voided = VoidFunction(derived, x);
bool out = voided();
if ((x == 3) and (out == true)) {
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}
Edits:
Fixed typo in final test (out == false) became (out == true)
Firstly, from the compiler's point of view CrtpBase<D>::template Run<Args ...> is a nonsensical/incomplete combination of tokens. There's no such expression syntax in C++. This looks like an attempt to form a pointer-to-member, but that requires an explicit application of & operator
return std::bind(&CrtpBase<D>::template Run<Args ...>, base, std::forward<Args> (args) ...);
Secondly, this cast
static_cast<D&>(*this)
will attempt to cast away constness. This is not allowed in static_cast.
Thirdly, your
std::bind(&CrtpBase<D>::template Run<Args ...>, base, std::forward<Args> (args) ...);
binds the implied this parameter to a function parameter base. This will not work, since the base will be destroyed as soon as VoidFunction exits (or as soon as the calling expression ends). As #aschepler correctly noted in the comments passing base in as CrtpBase<D> value sliced the original CrtpDerived<int&> object. Pass it in by reference and then use &base as argument for std::bind.
Fourthly, std::bind will not bind "by reference", and std::forward will not help you with this. This means that a inside your lambda fn will not be bound to x. Use std::ref to work around that limitation.
#include <functional>
#include <utility>
template <typename D>
struct CrtpBase {
template <typename ... Args>
bool Run(Args&& ... args) const {
return static_cast<const D&>(*this).Impl(std::forward<Args>(args) ...);
}
};
template <typename ... Args>
struct CrtpDerived : public CrtpBase<CrtpDerived<Args ...>> {
CrtpDerived(std::function<bool(Args ...)> function) : runable(std::move(function)) {}
bool Impl(Args&& ... args) const {
return this->runable(std::forward<Args>(args) ...);
}
std::function<bool(Args ...)> runable;
};
template <typename D, typename ... Args>
std::function<bool()> VoidFunction(CrtpBase<D> &base, Args&& ... args) {
return std::bind(&CrtpBase<D>::template Run<Args ...>, &base, std::forward<Args>(args) ...);
}
int main(int argc, char** argv) {
std::function<bool(int&)> fn = [](int& a)->bool { a /= 2; return (a % 2) == 1; };
CrtpDerived<int&> derived(fn);
int x = 7;
auto voided = VoidFunction(derived, std::ref(x));
bool out = voided();
if ((x == 3) && (out == false)) {
return EXIT_SUCCESS;
} else {
return EXIT_FAILURE;
}
}
One last thing: I don't understand why you expect your out to be false in the end.

How to specialize template pack?

I have the following code, which tries to convert a binary number (passed as a list of booleans, least-significant first, variable lenght) into a decimal number:
#include <iostream>
using namespace std;
template<typename T>
int bin_to_dec(int multi, T first) {
cout<<"mutli"<<multi<<endl;
return first?multi:0;
}
template<typename T, typename... Args>
int bin_to_dec(int multi, T first, Args... args) {
cout<<"mutli"<<multi<<endl;
return (first?multi:0) + adder(multi*2, args...);
}
template<typename T, typename... Args>
int bin_to_dec(T first, Args... args) {
cout<<"mutli"<<1<<endl;
return (first?1:0) + adder(2, args...);
}
int main()
{
cout<<bin_to_dec(true, true, false, true)<<endl;
}
It works quite well, but I would like to make it possible only for booleans, so when I try something like bin_to_dec(1,2,3) it should not compile. I was trying to use something like
template<bool First, bool... Bools>
but I can't figure out how to go further with that. Any ideas?
The obvious approach is to remove the function from the overload set for all template arguments but bool:
template <typename... T>
std::enable_if_t<variadic_and(std::is_same<T, bool>::value...), int>
bin_to_dec(T... bits) {
// probably delegate to differently named functions as an implementation detail
// ...
}
variadic_and() would be a constexpr function returning true if all its arguments are true:
constexpr bool variadic_and() { return true; }
template <typename... T>
constexpr bool variadic_and(bool v, T... vs) {
return v && variadic_and(vs...);
}
With C++17 variadic_and() would be necessary as parameter packs can be expanded with an operator. For example, the implementation of variadic_and() could look like this:
template <typename... T>
constexpr bool variadic_and(T... vs) { return (vs && ...); }
The same approach could be used directly within std::enable_if_t<...>.
Note: the approaches used above requires that the arguments are deduced as bool, i.e., they pretty much need to be of type bool. Since the function shouldn't be callable with int parameters and these would convert to bool, testing whether the argument type is convertable to bool doesn't seem appropriate. However, it may be reasonable to allow some conversions. If so, a corresponding trait would be used in the first paramter to std::enable_if_t.
Just use a static assert. This works perfectly well:
int bin_to_dec() {
return 0;
}
template<typename T, typename ... Args>
int bin_to_dec(T first, Args ... rest)
{
static_assert(std::is_same<bool, T>::value, "Only valid for bools");
return (first ? 1 : 0) + (bin_to_dec(rest...) << 1);
}
int main()
{
cout<<bin_to_dec(true, true, false, true)<<endl;
cout<<bin_to_dec(1, 2, 3)<<endl; //compile error
}

Passing an integer or a type as a template parameter?

Here is an example case of what I'm trying to do (it is a "test" case just to illustrate the problem) :
#include <iostream>
#include <type_traits>
#include <ratio>
template<int Int, typename Type>
constexpr Type f(const Type x)
{
return Int*x;
}
template<class Ratio, typename Type,
class = typename std::enable_if<Ratio::den != 0>::type>
constexpr Type f(const Type x)
{
return (x*Ratio::num)/Ratio::den;
}
template</*An int OR a type*/ Something, typename Type>
constexpr Type g(const Type x)
{
return f<Something, Type>(x);
}
int main()
{
std::cout<<f<1>(42.)<<std::endl;
std::cout<<f<std::kilo>(42.)<<std::endl;
}
As you can see, there are two versions of the f() function : the first one takes an int as a template parameter, and the second one takes a std::ratio. The problem is the following :
I would like to "wrap" this function through g() which can take an int OR a std::ratio as first template parameter and call the good version of f().
How to do that without writing two g() functions ? In other words, what do I have to write instead of /*An int OR a type*/ ?
Here's how I would do it, but I've changed your interface slightly:
#include <iostream>
#include <type_traits>
#include <ratio>
template <typename Type>
constexpr
Type
f(int Int, Type x)
{
return Int*x;
}
template <std::intmax_t N, std::intmax_t D, typename Type>
constexpr
Type
f(std::ratio<N, D> r, Type x)
{
// Note use of r.num and r.den instead of N and D leads to
// less probability of overflow. For example if N == 8
// and D == 12, then r.num == 2 and r.den == 3 because
// ratio reduces the fraction to lowest terms.
return x*r.num/r.den;
}
template <class T, class U>
constexpr
typename std::remove_reference<U>::type
g(T&& t, U&& u)
{
return f(static_cast<T&&>(t), static_cast<U&&>(u));
}
int main()
{
constexpr auto h = g(1, 42.);
constexpr auto i = g(std::kilo(), 42.);
std::cout<< h << std::endl;
std::cout<< i << std::endl;
}
42
42000
Notes:
I've taken advantage of constexpr to not pass compile-time constants via template parameters (that's what constexpr is for).
g is now just a perfect forwarder. However I was unable to use std::forward because it isn't marked up with constexpr (arguably a defect in C++11). So I dropped down to use static_cast<T&&> instead. Perfect forwarding is a little bit overkill here. But it is a good idiom to be thoroughly familiar with.
How to do that without writing two g() functions ?
You don't. There is no way in C++ to take either a type or a value of some type, except through overloading.
It is not possible to have a template parameter taking both type and non-type values.
Solution 1:
Overloaded functions.
Solution 2:
You can store values in types. Ex:
template<int n>
struct store_int
{
static const int num = n;
static const int den = 1;
};
template<class Ratio, typename Type,
class = typename std::enable_if<Ratio::den != 0>::type>
constexpr Type f(const Type x)
{
return (x*Ratio::num)/Ratio::den;
}
template<typename Something, typename Type>
constexpr Type g(const Type x)
{
return f<Something, Type>(x);
}
But with this solution you will have to specify g<store_int<42> >(...) instead of g<42>(...)
If the function is small, I advise you to use overloading.