Maybe it's flu, or I'm just plain stupid, but I can't understand a part of this Crow framework code. My inner C++ parser fails.
template <typename MW>
struct check_before_handle_arity_3_const
{
template <typename T,
//this line
void (T::*)(int, typename MW::context&) const = &T::before_handle
>
struct get
{ };
};
I know it's a template parameter inside template declaration. It looks like maybe some lambda or function pointer type parameter... but, I'm not sure.
Can someone explain this line?
Update:
Exploring depths of newly obtained knowledge - after the answer was given - led me to this excerpt from a great book:
A template can accept a pointer to a function as a nontype template
parameter. (Most often in this book, nontype template parameters are
integral values.) [...] Using a pointer to a function as a nontype
template argument means that we no longer need to store it in the map.
This essential aspect needs thorough understanding. The reason we
don't need to store the pointer to a function is that the compiler has
static knowledge about it. Thus, the compiler can hardcode the
function address in the trampoline code.
So, now I know one of the reasons to use this technique.
void (T::*)(int, typename MW::context&) const is a non-type template parameter.
It is a pointer to a member function of T.
With the use of = &T::before_handle, its default value is set to &T::before_handle.
The reason I used this technique is to support 2 kinds of handler format:
https://github.com/ipkn/crow/blob/master/include/middleware.h#L17
check_before_handle_arity_3_const is used here:
template <typename T>
struct is_before_handle_arity_3_impl
{
template <typename C>
static std::true_type f(typename check_before_handle_arity_3_const<T>::template get<C>*);
template <typename C>
static std::true_type f(typename check_before_handle_arity_3<T>::template get<C>*);
template <typename C>
static std::false_type f(...);
public:
static const bool value = decltype(f<T>(nullptr))::value;
};
With SFINAE, is_before_handle_arity_3_impl<T>::value is determined whether we can call the handler with 3 arguments or not. By using std::enable_if, Crow can call the proper handler:
https://github.com/ipkn/crow/blob/master/include/http_connection.h#L110
Related
I have inherited the following:
template <typename T>
concept IsAwaiter = requires {
typename T::await_ready;
typename T::await_suspend;
typename T::await_resume;
};
template <typename ...AWAITABLES>
concept IsAwaitables = typename std::conjunction<IsAwaiter<AWAITABLES>...>::type;
Building this with clang 10.0.0 results in the following error:
IsAwaiter.h:43:50: error: template argument for template type parameter must be a type
Perhaps just a simple syntax issue, but I've found it hard to find an example which shows how to create a concept based on a variadic template concept parameter.
Any help appreciated!
std::conjunction is for type traits. std::conjunction<IsAwaiter<AWAITABLES>...> is a type with a member static bool value = (IsAwaiter<AWAITABLES>::value && ...), where each IsAwaiter<AWAITABLES> is itself expected to be a type trait with its own static bool member value. This is nonsensical when IsAwaiter<AWAITABLES> is a concept, because concepts are not type traits. They are "just" booleans. Use a fold expression.
template <typename... AWAITABLES>
concept IsAwaitables = (IsAwaiter<AWAITABLES> && ...);
That's it.
struct Dummy {
using await_ready = Dummy;
using await_suspend = Dummy;
using await_resume = Dummy;
};
int main() {
static_assert(IsAwaitables<>);
static_assert(IsAwaitables<Dummy>);
static_assert(IsAwaitables<Dummy, Dummy>);
}
As HTNW points out, you want:
template <typename ...T>
concept IsAwaitables = (IsAwaiter<T> && ...);
But really, do you even need this concept at all? You can just use IsAwaiter directly. And it probably should just be named Awaiter - the typical convention for concepts is to name them as nouns rather than questions (e.g. Range vs IsRange).
If you're taking a parameter pack, you would want to use it anyway:
template <Awaiter... T>
void f(T... awaiters);
and the same with the abbreviated function template syntax:
void f(Awaiter auto... awaiters);
or if you have a fixed number of them, it especially doesn't make sense:
template <Awaiter T, Awaiter U>
void f(T, U);
And even in other contexts where it doesn't neatly fit, it seems better to just manually use Awaiter with a fold-expression. So I question the need for the conjunction concept to begin with.
I'm making an entity-component system library utilizing template metaprogramming to evaluate signature bitset data at compile-time and allow for precise bitset size without using #define MAX_COMPONENTS some-number.
I'm using Boost Hana and have a function which should look like this:
template <auto T>
static constexpr Bitset signatureBitset = Bitset(
hana::fold(SignatureList[hana::integral_c<std::size_t, signatureID<T>>], 0,
[](auto l, auto r) {
return l | 1 << inferProperty<primitiveBit>(r);
}));
What it does is calculate constexpr Bitset for given signature. Signature is a hana::tuple_t of ECS component and tag types.
primitiveBit returns bit offset of template argument type component/tag. As hana::fold lambda doesn't provide type of current r, I can't simply call primitiveBit<RType> (RType is not defined).
Simplest possible solution would be to write a duplicate of every template "function" but as an actual constexpr function instead of static constexpr object but I'm trying to avoid that as writing 30+ duplicate function which all do
template <typename T>
static constexpr auto inferFunctionName(hana::basic_type<T> t) {
return functionName<T>;
}
seems dumb and will make everything harder to maintain. The above code also looks very simple and like it can be abstracted away using template function taking template constexpr object as a template parameter.
This is what I currently have:
template <template<typename> typename TReturn, typename T>
constexpr auto inferProperty(hana::basic_type<T> t) {
return TReturn<T>();
}
inferProperty<primitiveBit>(r) throws a compile error saying it doesn't match defined template signature.
Using template <template<typename T> typename TReturn, typename T> isn't an option due to T not being defined within lambdas.
Simple solution, as said by Jack C. in the comments, is to use decltype(r) inside lambda to get type from object instead of inferring type through template functions.
Which means propertyCheck<typename decltype(r)::type> works.
The short version (Read if you have no patience like me):
What does setting a typename template parameter to a default of 0 do in C++?
My enable if struct:
/**
* #brief Can be used to enable a template definition using a boolean value
*/
template<lfBool Condition>
struct lfEnableIf
{ };
template<>
struct lfEnableIf<true>
{
typedef lfInt Type;
};
My boolen constant struct:
template<lfBool Val>
struct lfBoolConstant
{
static const lfBool Value = Val;
};
typedef lfBoolConstant<true> lfTrueType;
typedef lfBoolConstant<false> lfFalseType;
My type trait struct (just one of the specializations):
template <typename NumT> struct lfIsArithmetic : lfFalseType{};
template <> struct lfIsArithmetic<lfChar> : lfTrueType{};
And finally my usage of it all:
template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>
struct Test
{
static void print()
{
std::cout << "OK!" << std::endl;
}
};
int main()
{
Test<lfFloat>::print();
Test<lfBool>::print();
return 0;
}
Sorry for the poor for formatting I am writing this on my cell phone.
The long version (Please read if you have the patience so you understand why there is not much code):
So, I am on vacation and don't have access to my workstation or laptop so I thought I would try out AIDE, which if you are unaware is an IDE for android that can compile C++. At home I am designing a game engine that includes Boost and I figured I would try to create something similar to the enable_if structures that are in the Boost.Core library. I got it mostly working but it would not compile unless I set the enable if structure in the template I was enabling to default to 0! This is what you do with the Boost enable_if and disable_if templates. So what does setting a typename template parameter to a default of 0 do in C++?
Thanks!
This line
template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0>
declares a named template type parameter T and a nameless template value parameter of type lfEnableIf<lfIsArithmetic<T>::Value>::Type, i.e. the second parameter declarations is basically a more convoluted version of simple
template <int N = 0> struct S {};
The type lfEnableIf<lfIsArithmetic<T>::Value>::Type resolves into type lfInt when the enabling condition is met, meaning that the whole thing in such cases is equivalent to
template<typename T, lfInt = 0>
However, since type of that second template parameter is a nested type of a dependent template lfEnableIf, you are required to use the keyword typename to tell the compiler that member Type actually refers to a type and not to something else (i.e. to disambiguate the situation).
Again, the second parameter of the template is nameless, but you can give it a name, if you wish. It won't change anything
template<typename T, typename lfEnableIf<lfIsArithmetic<T>::Value>::Type V = 0>
In the above example I called it V. The name of that parameter is not used anywhere in the template, which is why there's no real need to specify it explicitly. It is a dummy parameter, which is also the reason it has a dummy default value (you can replace 0 with 42 - it won't change anything either).
In this case keyword typename creates a misleading similarity between the two parameter declarations of your template. In reality in these parameter declarations the keyword typename serves two very very very different unrelated purposes.
In the fist template parameter declaration - typename T - it declares T as a template type parameter. In this role keyword typename can be replaced with keyword class
template <class T, ...
In the second declaration - typename lfEnableIf<lfIsArithmetic<T>::Value>::Type = 0 - it serves a secondary purpose - it just tells the compiler that lfEnableIf<lfIsArithmetic<T>::Value>::Type is a type and thus turns the whole thing into a value parameter declaration. In this role keyword typename cannot be replaced with keyword class.
How do I create a metafunction that takes any kind of function pointer? In the code below, how do I get rid of "decltype(&f)" ?
template <class FuncType, FuncType functionPointer>
void runFunc()
{
functionPointer();
}
runFunc<decltype(&f),f>();
I don't want to have to specify the type of f seperately; the information is already there in f. I'd prefer not to resort to defines to solve this.
This is basically the templated function type idiom applied to meta-programming; I don't want to know the type of f, but whatever I get in apparently allows me to call operator() on it.
Stuff I've tried:
Different order for the template parameters; since later parameters seem to be guessable when you have a function; not possible because then you would need to forward declare FuncType, in order to have it as the type for functionPointer
Switching it around so that you specify returntype and parameters and give a function pointer of that type; cannot instantiate a template with variable template arguments in the middle; that looks like below:
template <class ReturnType, class ... ArgTypes, ReturnType (*functionPointer)(ArgTypes...)>
void runFunc()
{
functionPointer();
}
runFunc<void, int, f>(); // error; invalid template argument for 'ArgTypes', type expected
There's a bit more context here on github: https://github.com/TamaHobbit/FuncTest/blob/master/FuncTest/FuncTest.cpp
You can use this:
template <typename FuncType>
void runFunc(FuncType functionPointer )
{
functionPointer();
}
runFunc(f);
Right now there is unfortunately no good way of doing this.
The standard committee has, however, accepted a proposal that makes this valid code:
template <auto functionPointer>
void runFunc() {
functionPointer();
}
Compiler support should be coming soon.
I have learned that data structures can be created using templates in the following way:
template<typename T>
struct X {
T weight;
int age;
};
The functions can also use templates in the following way:
template <class T>
T func_name(int age, T human) {
something_here;
}
One of the difference s is that in the first case we use typename while in the second case we use class.
I found code that contains the following:
template<typename S, typename T>
bool is_null(const row<T>& r)
So, what I cannot understand is why we use typename (and not class) in combination with functions. Shouldn't we use class?
In this context, there is no technical difference between the keyword typename and the keyword class. It's just a matter of style. The meaning of your first two code examples would not change one bit if they started with template<class T> struct X and template <typename T> T func_name(int age, T human). (I tend to use class when I mean to imply the template parameter should be a class, and not something like int.)
When template was first introduced, it ONLY allowed the existing keyword class as an indicator "this is a template argument". Since this becomes rather daft when the template argument isn't actually a class (a function pointer, integer type, or some other "not a class" type), the typename was introduced to make it more clear that template<typename T> struct something { T x; }; allows something<int> a; as well as something<name_of_class> a;.
For all intents and purposes, class and typename in the case of template parameters is interchangeable, and it's just a matter of style which you choose to do [most people probably prefer if you stick to one, not mixing the two - or, perhaps use class when the type HAS TO be a class, and typename when it can be "any" type].
In the context of template parameter definitions the keywords typename and class are synonymous.
Just about everyone has a convention they tend to stick with. I personally prefer to always use class here and reserve the typename keyword for its other use.
The other use for typename is to disambiguate a dependent type in a template definition or declaration.
Here is an example from wikipedia:
template <typename T>
void foo(const T& t)
{
// declares a pointer to an object of type T::bar
T::bar * p;
}
struct StructWithBarAsType {
typedef int bar;
};
int main() {
StructWithBarAsType x;
foo(x);
}
If you look closely you will notice in the line T::bar * p;, bar is dependent on a template parameter T which is ambiguous to the compiler as bar can be either a type or a value depending on the context of the type T used for instantiating the template. The default is to treat bar as a value so the meaning would be to multiply T::bar by p which is not what we want.
The solution is to qualify the dependent type with the typename keyword.
typename T::bar * p;
This alerts the compiler to the fact that we intend to treat bar as a type.
There's only one spot where they differ (when declaring template parameters), and that is when using template-templates.
The following is well-defined C++
template <template <typename> class TT> struct example_one {};
while this is not:
template <template <typename> typename TT> struct example_two {};
Since it seems like you're just starting out with C++/templates, this corner case won't concern you for a while :-) Aside from the above, class template, function template, it doesn't matter: typename and class are synonymous.