Convert template parameter into comma-separated list of template parameters - c++17

Apologies if the title is misleading or if this question has been answered before.
I'm working with Eigen's Tensor module, particularly the Eigen::TensorFixedSize class as I know the shape at compile time.
Essentially, because this is a Lorentz problem, a rank-2 tensor would go like,
Eigen::TensorFixedSize<double, Eigen::Sizes<4,4>> t;
a rank-3 tensor,
Eigen::TensorFixedSize<double, Eigen::Sizes<4,4,4>> t;
and so on.
I'd like to write a class that is able to initialise a tensor depending on the rank. In pseudo-code,
template<typename RANK>
class Foo
{
public:
...
private:
Eigen::TensorFixedSize<double, Eigen::Sizes<4,4,4,...,RANK times>> _t;
}
somehow converting the template parameter from
<2> --> <4,4>
<3> --> <4,4,4>
up to an arbitrary unsigned int in <N>.
Would this be possible to do?

Yup.
template <class RankIdx>
struct TensorForRank;
template <std::size_t... RankIdx>
struct TensorForRank<std::index_sequence<RankIdx...>> {
using type = Eigen::TensorFixedSize<double, Eigen::Sizes<(void(RankIdx), 4)...>>;
};
template <std::size_t Rank>
using TensorForRank_t = typename TensorForRank<std::make_index_sequence<Rank>>::type;
Use as:
template<std::size_t Rank>
class Foo
{
// ...
private:
TensorForRank_t<Rank> _t;
};
See it live on Wandbox (with a placeholder test<...> template as Eigen is not available)

Quentin's answer is very good, and what I'd go with.
The only downside is the "useless" generation of an index sequence [0, 1, 2, ...] whose values we ignore, and substitute for our own.
If we want to directly create the repeated values, we can write our own generator code (which is quite a bit more verbose):
Start with creating a type that can hold a number of std::size_t values by aliasing a std::integer_sequence:
template<std::size_t... vals>
using value_sequence = std::integer_sequence<std::size_t, vals...>;
The goal is to ultimately create a value_sequence<4, 4, 4> and then instantiate an Eigen::Sizes using those 4s.
The next thing we need to be able to do is concatenate two sequences, because we're going to build it up like so:
concat(value_sequence<4>, value_sequence<4>) --> value_sequence<4, 4>
We can do this via a stub method that accepts two value_sequence types and returns the concatenated result. Note that we do not ever write a definition for this method; we're simply taking advantage of the type system to write less code than a template specialization would take:
template<std::size_t... lhs, std::size_t... rhs>
constexpr auto concat(value_sequence<lhs...>, value_sequence<rhs...>) -> value_sequence<lhs..., rhs...>;
At this point we have enough machinery to create a value_sequence<4,4,4>, so now we need a way to indicate the value we wish to use (4) and the number of times to repeat it (3) to produce it:
template<std::size_t value, std::size_t num_repeats>
struct repeated_value
{
using left_sequence = value_sequence<value>;
using right_sequence = typename repeated_value<value, num_repeats-1>::type;
using type = decltype(concat(left_sequence{}, right_sequence{}));
};
repeated_value<4, 3>::type produces a value_sequence<4, 4, 4>.
Since repeated_value<...>::type is recursive, we need to provide a base case via partial specialization:
template<std::size_t value>
struct repeated_value<value, 1>
{
using type = value_sequence<value>;
};
Great. All that's left is for us to receive an Eigen::Sizes class and a value_sequence<4, 4, 4> type, and produce Eigen::Sizes<4, 4, 4>.
We can do this with partial template specialization again:
template<template<std::size_t...> class T, class...>
struct InstantiateWithRepeatedVals;
template<template<std::size_t...> class T, std::size_t... vals>
struct InstantiateWithRepeatedVals<T, value_sequence<vals...>>
{
using type = T<vals...>;
};
That it! Throw in a few helpers to make using it easier, and we're done:
template<std::size_t value, std::size_t num_repeats>
using repeated_value_t = typename repeated_value<value, num_repeats>::type;
template<template<std::size_t...> class T, std::size_t Value, std::size_t N>
using InstantiateWithRepeatedVals_t = typename InstantiateWithRepeatedVals<T, repeated_value_t<Value, N>>::type;
Now we can use it like so:
using my_type = InstantiateWithRepeatedVals_t<EigenSizes, 4, 3>;
static_assert(std::is_same_v<my_type, EigenSizes<4, 4, 4>>);
Live Demo

Related

Why to use this specific type of constructor in Dart?

I am starting to learn dart using their own documentation from here : constructors
I came across this type of contractor :
Vector2d.named({required this.x, required this.y});
They have not specified what this does or how it works. they only showed this in a small snippet with no clarification. Can someone please elaborate how this contractor works and what is the difference between a normal C-styled constructor and this one?
I tried googling about this style of constructor but couldn't get much because of the special characters in the syntax.
You can head to DartPad and paste the code below to try it.
class Vector2d {
final double x;
final double y;
Vector2d(this.x, this.y);
Vector2d.named({required this.x, required this.y});
}
main() {
var v1 = Vector2d(1, 2);
var v2 = Vector2d.named(x:3, y:4);
var v3 = Vector2d.named(y:5, x:6);
}
v1 is created using a "normal" constructor: first parameter will be assigned to x, the second to y.
v2 is created using a so called named constructor, where you have to specify which variable will get which value. The order here is irrelevant, see v3. Named constructors are also handy when you have to deal with a large number of parameters.
The required keyword means it is a required parameter. If you remove the required keyword, you will get an error that x and y can't have a value of null, because you no longer forced to specify x and y, they can be null. To fix this you can make the type nullable by adding a ? after the type:
class Vector2d {
final double? x;
final double? y;
Vector2d([this.x, this.y]);
Vector2d.named({this.x, this.y});
}
main() {
var v4 = Vector2d(1);
var v5 = Vector2d.named(x:5);
var v6 = Vector2d.named(y:6);
}
This also makes x and y named optional parameters: you are not forced to initialise them, but keep in mind that you need to check them before using them (because they're null). v5 and v6 are created with named constructor, and one of their member is null. Try and see what happens when you print out v5.x and v5.y.
You can also have positional optional parameters. Notice the [] in the first constructor. v4 is created with positional optional constructor. This means that you can have zero, one or two positional arguments when you use that constructor. See what happens when you print out v4.x and v4.y.
And lastly: you can mix these named and positioned optional parameters with required ones:
class Mixed {
final int? x;
final int? y;
final int? z;
Mixed.namedOptional(this.x, {required this.y, this.z});
Mixed.positionalOptional(this.x, [this.y, this.z]);
}
And note that these rules apply to any regular functions, not just constructors!
I suggest to watch this video to understand null and null safety in dart and see this and this other answers related to the topic

Clang AST matching method call on class, derived class or typedef to either

I have a matcher that works perfectly for matching operator() calls on instances of a class or classes derived from that class. For example, it matches the final line of:
class MyBase { void operator()(...) {} };
MyBase b;
b(parameters);
using a matcher like:
const auto MyBaseExpr =
expr(hasType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));
Finder->addMatcher(traverse(
TK_AsIs, cxxOperatorCallExpr(
hasOverloadedOperatorName("()"),
hasArgument(0, anyOf(MyBaseExpr, MyOtherBaseExpr)),
hasAnyArgument(...),
this);
But I'd also like to be able to match such calls on instances of typedefs for the base or derived types like in the last line below:
typedef MyBase MyTypedef;
MyTypedef t;
t(parameters);
and I can't seem to fathom the correct way to specify this match. Attempting to use hasUnqualifiedDesugaredType rather than hasType doesn't work since it works on a type rather than a Decl and if I try to do more matching with the type then I can't use isSameOrDerived which returns a Matcher<CXXRecordDecl>. A similar problem occurs when trying to use hasCanonicalType:
.../RedundantStringCStrCheck.cpp:193:40: error: invalid initialization of reference of type ‘const clang::ast_matchers:
:internal::Matcher<clang::QualType>&’ from expression of type ‘clang::ast_matchers::internal::BindableMatcher<clang::Decl>’
193 | expr(hasCanonicalType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));
MyTypedef is defined from MyBase so its Canonical Type should be MyBase. More information about canonical type: https://clang.llvm.org/docs/InternalsManual.html#canonical-types
This is the example from LibASTMatchersReference , it uses hasType().
Thien Tran provided the pointer which led me to the right answer. Here's my original expression
const auto MyBaseExpr =
expr(hasType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));
I was trying to use:
const auto MyBaseExpr =
expr(hasCanonicalType(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))));
but the description of hasCanonicalType in LibASTMatchersReference shows that it takes and returns Matcher<QualType> yet cxxRecordDecl has type Matcher<Decl>, so this did not compile.
The mismatch of types can be corrected by inserting a call to hasDeclaration. It's then also necessary to keep the call to hasType in order to turn the Matcher<QualType> result of hasCanonicalType back into something that can be passed to expr.
After all that I ended up with:
const auto MyBaseExpr =
expr(hasType(hasCanonicalType(hasDeclaration(cxxRecordDecl(isSameOrDerivedFrom("::MyBase"))))));
which seems to work perfectly.

Does the using declaration allow for incomplete types in all cases?

I'm a bit confused about the implications of the using declaration. The keyword implies that a new type is merely declared. This would allow for incomplete types. However, in some cases it is also a definition, no? Compare the following code:
#include <variant>
#include <iostream>
struct box;
using val = std::variant<std::monostate, box, int, char>;
struct box
{
int a;
long b;
double c;
box(std::initializer_list<val>) {
}
};
int main()
{
std::cout << sizeof(val) << std::endl;
}
In this case I'm defining val to be some instantiation of variant. Is this undefined behaviour? If the using-declaration is in fact a declaration and not a definition, incomplete types such as box would be allowed to instantiate the variant type. However, if it is also a definition, it would be UB no?
For the record, both gcc and clang both create "32" as output.
Since you've not included language-lawyer, I'm attempting a non-lawyer answer.
Why should that be UB?
With a using delcaration, you're just providing a synonym for std::variant<whatever>. That doesn't require an instantiation of the object, nor of the class std::variant, pretty much like a function declaration with a parameter of that class doesn't require it:
void f(val); // just fine
The problem would occur as soon as you give to that function a definition (if val is still incomplete because box is still incomplete):
void f(val) {}
But it's enough just to change val to val& for allowing a definition,
void f(val&) {}
because the compiler doesn't need to know anything else of val than its name.
Furthermore, and here I'm really inventing, "incomplete type" means that some definition is lacking at the point it's needed, so I expect you should discover such an issue at compile/link time, and not by being hit by UB. As in, how can the compiler and linker even finish their job succesfully if a definition to do something wasn't found?

A few questions about Dart generics and type safety

I have the following Dart 2 code with null-safety.
extension Foo<T> on List<T> {
List<U> bar<U>({
U Function(T)? transform,
}) {
final t = transform ?? _identityTransform;
return map(t).toList();
}
}
U _identityTransform<T, U>(T t) => t as U; // #1, #2
void main() {
final strings = ['a', 'b', 'c'].bar<String>(); // #3
final ints = ['1', '2', '3'].bar(transform: int.parse);
print(strings);
print(ints);
}
It is an extension method on List<T> with a custom method that is basically a map with the
difference that it can return a new list of the same type if no transform is specified. (My real code is more complex than this, but this example is enough to present my questions.)
I want to be able to call bar() on a List with transform or without; if called without it, _identityTransform should be used.
The code above works, but I have a few reservations as to its quality, and questions, as I haven't really come to terms with Dart generics yet:
In the line marked #1 - the _identityTransform takes two generic parameters as I need access to them, but when the function is used the generic types are not used because I don't think it is possible to write something like _identityTransform<T, U> there. Is there a better way of defining _identityTransform? Am I losing any type safety with my current code?
In the line marked #2 I need a cast as U for the code to compile, I haven't managed to make the code work without it. Is there a way to do it without the cast?
In the line marked #3, when I call the extension method without any transform (i.e. I want the identity transform to kick in) I need to explicitly pass the generic type, otherwise the compiler complains about missing generic type (in strong mode) or infers strings to be List<dynamic> (strong mode turned off). Is some generics magic possible to be able to call .bar() and still have strings be inferred to List<String>?
I would make _identityTransform a nested function of bar so that you can remove its type arguments and instead use the same T and U as bar:
extension Foo<T> on List<T> {
List<U> bar<U>({
U Function(T)? transform,
}) {
U _identityTransform(T t) => t as U;
final t = transform ?? _identityTransform;
return map(t).toList();
}
}
Alternatively if you want to explicitly use _identityTransform<T, U>, then you could use a closure: t = transform ?? (arg) => _identityTransform<T, U>(arg), but that seems like overkill.
You need the cast. T and U are independent/unrelated types. Since you don't know that you want T and U to be the same until bar checks its argument at runtime, you will need the explicit cast to satisfy static type checking.
If the caller passes nothing for the transform argument, there is nothing to infer U from, so it will be dynamic. I can't think of any magical way make U default to T in such a case (again, that would be known only at runtime, but generics must satisfy static analysis).

Can record constructors make record constants more concise?

I have some tabular data:
Foo Bar
-------------
fooes 42
bars 666
...
So, I declare the entity structure:
type TFoo = record
Foo: string;
Bar: Integer
end;
and the table of entities:
const FOOES = array [M..N] of TFoo = (
// Have to specify the field names for each record...
(Foo: 'fooes'; Bar: 42),
(Foo: 'bars'; Bar: 666)
{ so on }
);
As you see, this looks quite verbose and redundant, and it is because I initialize all of the fields for all of the records. And there is a lot of editing if I copy tabular data prepared elsewhere. I'd prefer to not enumerate all of the fields and stick to the more laconic C style, that is, constants only. And here comes the record constructor...
Can record constructors help me in this case?
Here's an example in C. You'll notice that we don't have to specify the field names in each declaration:
#include <stdio.h>
typedef struct {
char foo[10];
int bar;
} foo;
int main(void) {
/* Look here */
foo FOOES[2] = {{"foo", 42}, {"bar", 666}};
int i = 0;
for (; i < 2; i++) {
printf("%s\t%d\n", FOOES[i].foo, FOOES[i].bar);
}
return 0;
}
A const is just a read-only var which is loaded/mapped within the code, when the executable is launched.
You can create a var record (or a const but overriding the writable const option), then initialize it in the initialization section of the unit.
var FOOES = array [M..N] of TFoo;
....
initialization
SetFooArray(FOOES,['fooes',42,'bar',230]);
...
end.
The custom SetFooArray() function will put all array of const parameters into FOOES.
I use this technique sometimes to initialize computable arrays (e.g. conversion or lookup tables). Sometimes, it does make sense to compute once at startup a huge array, saving some KB of const in the source code, with a few lines of code.
But I'm not sure it will be worth it in your case. The default const declaration is a bit verbose, but not a problem if you use Ctrl+C/Ctrl+V or a find and replace. It is the most standard, is secure if you change later the record layout (whereas the C construction may compile without error), and will create a true constant.
Record constructors are runtime only and so for constants your current solution is the only option.
If you want it done in source then what you have already typed is your answer. You could, of course, put the data in separate arrays and initialize them that way, but that can make your code look messy.
You could also store them in an text file (Foo=Bar format) and read them into a TStringList at run-time (SL.LoadFromFile()). But even with a sorted TStringList it will be far less efficient (MyVariable := SL.Values['Foo1']; for example).
There are a million ways to solve this problem outside of source code. Taking it from the other direction, put the data into Excel and create an Excel macro to build the source and put it into the clipboard to paste into your PAS file. This wouldn't be too difficult and probably easier than formatting the Delphi code within the IDE.

Resources