C++ Runtime variable in templates - c++

template <int ns, int id>
class Bar
{
public:
static int value;
};
template <int ns, int id>
int Bar<ns, id>::value = 0;
class Foo
{
public:
template <int ns, int id>
static int GetNextValue()
{
++Bar<ns, id>::value;
return Bar<ns, id>::value;
}
};
class Baz
{
public:
Baz(int value)
: value(value)
{
}
void PrintBaz();
private:
int value;
};
This works fine when called like:
Baz baz(Foo::GetNextValue<1, 1>());
I need this code to support the following.
int ns = 1;
int id = 5;
Baz baz(Foo::GetNextValue<ns, id>());
Compilation for this code fails understandably. Is there a way to have template meta-programming support runtime variable values?
Pointer to solution for this problem by any other method will also be helpful.

The simple answer is no, templates are a compile time construct. You might want to consider constexpr functions if you need code that can be evaluated at compile time or runtime.

A template meta programm "runs" during compilation. So every input into it must be known at compile time.
Think of this:
template<int N>
int get(void) {
return N;
}
This creates a completely new function on each instantiation with a different value for N. So if the passed value of some instantiation isn't known at compile time, this would mean that the new function had to be generated during runtime. For this to work you'd need the compiler to be part of your final application. It might seem simple in this case, but there are pretty complex meta programms out there.
Moreover, even the syntax of C++ depends on the results of some meta programms:
template<bool = true>
struct switch {
template<int>
using thing = int;
};
template<>
struct switch<false> {
int thing = 21;
}
switch<META>::thing<42>(21);
// bool result of comparisons: 21 < 42 > 21
// or int result from cast: 21

Related

Meet two generic values in one function

I have two callbacks foo and bar, both taking a generic value each.
When both callbacks has been called I want these values to meet in single function. My test code is:
template <class FooType, class BarType>
void meet_point(FooType foo_value, BarType bar_value) {
// Success
}
struct test
{
template <class FooType>
void foo(FooType value) {
// TODO: save value or type somehow
}
template <class BarType>
void bar(BarType value) {
meet_point(/* FooType value from above */, value);
}
};
template <class F>
void sync_request(F&& f) {
f("foobar");
}
int main()
{
test t;
sync_request([&t](auto value) {
t.foo(value);
});
t.bar(42);
}
Is there any way to do it?
EDIT:
Note that code in main() is just an example of calling both callbacks. Actual calls happens from different places and both triggers do not know anything about each other.
Also at the time of instantiating test object no type is known ahead. Actually test struct is not even needed here. It could be standalone callbacks. It is there just for maybe possible storage of FooType value.
P.S.
I wish we had reflection, jit, Circle #type_id or templated virtual functions to extract the type in C++.
You need to know (or be able to exhaustively list the possibilities of) at least one of FooType or BarType.
Case 1: FooType is one of typename... FooTypes known when you instantiate a test.
template<typename... FooTypes>
struct test
{
using FooType = std::variant<FooTypes...>;
void foo(FooType value) {
foo_value = value;
}
template <class BarType>
void bar(BarType value) {
std::variant<BarType> bar_value = value;
std::visit(meet_point, foo_value, bar_value);
}
FooType foo_value;
};
Case 2: BarType is one of typename... BarTypes known when you instantiate a test.
template<typename... BarTypes>
struct test
{
using BarType = std::variant<BarTypes...>;
template <class FooType>
void foo(FooType value) {
std::variant<FooType> foo_value = value;
visit = [foo_value](BarType bar_value){ std::visit(meet_point, foo_value, bar_value); };
}
void bar(BarType value) {
visit(value)
}
function<void(std::variant<BarTypes...>)> visit;
};
Case 3: FooType is one of typename... FooTypes and BarType is one of typename... BarTypes, both known when you instantiate a test.
template<typename... FooTypes, typename... BarTypes>
struct test
{
using FooType = std::variant<FooTypes...>;
using BarType = std::variant<BarTypes...>;
void foo(FooType value) {
foo_value = value;
}
void bar(BarType bar_value) {
std::visit(meet_point, foo_value, bar_value);
}
std::variant<FooTypes...> foo_value;
};
When you write your code you do not know which types the user of your library will use. But when the user compiles his types has to be known. If you are fine with letting the user register his types you can do it like this:
#include <boost/algorithm/algorithm.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/hana.hpp>
#include <functional>
#include <iostream>
#include <type_traits>
// code you write
struct CallbackData
{
virtual ~CallbackData () = default;
};
// code your user writes for example in userTypes.h
struct TestFooType : CallbackData
{
int value = 42;
};
struct TestBarType : CallbackData
{
std::string value{ "bar type" };
};
struct AnotherTestFooType : CallbackData
{
int value = 42;
};
struct AnotherTestBarType : CallbackData
{
std::string value{ "bar type" };
};
static boost::hana::tuple<TestFooType, TestBarType, AnotherTestFooType, AnotherTestBarType> const sharedClasses{};
// code you write
struct test
{
void
bothAreReady ()
{
boost::hana::for_each (sharedClasses, [&] (auto x) {
if (std::shared_ptr<std::decay_t<decltype (x)>> firstValue = std::dynamic_pointer_cast<std::decay_t<decltype (x)>> (fooValue))
{
std::cout << "fooValue: " << firstValue->value << std::endl;
return;
}
});
boost::hana::for_each (sharedClasses, [&] (auto x) {
if (std::shared_ptr<std::decay_t<decltype (x)>> secondValue = std::dynamic_pointer_cast<std::decay_t<decltype (x)>> (barValue))
{
std::cout << "barValue: " << secondValue->value << std::endl;
return;
}
});
}
bool
isDone ()
{
return fooValue && barValue;
}
std::shared_ptr<CallbackData> fooValue{};
std::shared_ptr<CallbackData> barValue{};
};
// code your user writes
int
main ()
{
test t;
auto fooAction = [&t] () {
auto testFooType = TestFooType{};
// do something with test foo type
t.fooValue = std::shared_ptr<CallbackData>{ new std::decay_t<decltype (testFooType)>{ std::move (testFooType) } };
if (t.isDone ()) t.bothAreReady ();
};
auto barAction = [&t] () {
auto testBarType = TestBarType{};
// do something with testBarType
t.barValue = std::shared_ptr<CallbackData>{ new std::decay_t<decltype (testBarType)>{ std::move (testBarType) } };
if (t.isDone ()) t.bothAreReady ();
};
// run the lambdas on some other thread or so
fooAction ();
barAction ();
}
wandbox example
Alice live in Australia. Alice creates a nice class Alice, writes a source file that contains a call to test.foo(Alice()), builds a DLL, and ships it to you.
Bob lives in Bermuda. Bob creates a nice class Bob, writes a source file that contains a call to test.bar(Bob()), builds a DLL, and ships it to you.
Alice and Bob have never heard of each other and have never seen each other's code.
You have your program load the two DLLs and...
Where is meet_point<Alice, Bob>?
It cannot be in Alice's DLL, because Alice have never seen Bob's code.
It cannot be in Bob's DLL, because Bob have never seen Alice's code.
It cannot be in your program, because you have never seen the code of either of them! All you have is their DLL that call your code. They both obviously have your header that defines struct test, but this doesn't help at all.
So you need some tool that would go over Alice's and Bob's code, extract all types that are used in calls to foo and bar, and instantiate meet_point<a, b> with every possible pair (a, b) of such types. The problem is, there isn't such tool in any standard toolkit. You need to write one somehow.
The easiest way would be asking Alice and Bob to send you a list of their types used in calls to foo and bar. You can also go over their object code and extract these types from symbols or whatever. In any case you need them to send you header files with definitions of all their classes, so that you can compile each instantiation. Another option (not as crazy as it sounds) would be just-in-time compilation: make your class find the headers (you can know the names of the classes so that's doable), generate a source that instantiates meet_point with relevant arguments, run the compiler, build a DLL, load it, and call the function! Cache the DLL for later use. Of course it could happen that meet_point cannot be compiled with a particular combination of arguments, and you will only know it when this combination arrives.
Now "two developers that do not talk to each other send you DLLs" is an extreme model of the situation, but it doesn't actually create any new problem. It just makes it easier to see problems that are inherent in the situation.

rvalue References and Template parameters

Why is this syntax not allowed:
template<float&& value>
struct MyStruct{
float GetValue() { return value; }
};
MyStruct<12.1f> myFloat;
And we have to instead do this:
template<const float& value>
struct MyStruct{
float GetValue() { return value; }
};
extern constexpr float param = 12.1f;
MyStruct<param> myFloat;
I don't see any reason why the first should be forbidden.
The first syntax is far less clunky and the second syntax just makes it seem like the creators of c++ are just trying to make things difficult....So why is it like this?
Because template processing is hugely complicated, I assume that the designers rightly rejected features that could be easily done using other means. Template parameters exist to customize the behavior of the code, not merely to insert constants. That's why int template parameters are supported, so you can do things like:
template <int SIZE> struct X {
char buffer[SIZE];
};
If you just want a constant in your instance of the class, add it to the constructor:
class X {
public:
X(float value_) {
value = value_;
}
float value;
};
If you really want a customized class that uses that constant, how about:
class X71 : public X {
public:
X71() : X(7.1f) {}
};

C++ template struct 'has no member named' error

The only way I can get this to compile without issuing a warning on no member a when T==B and so on for T==A is to reinterpret_cast within the if statement blocks and access the non-shared members via a pointer. Is there no way to get around this or hint to the compiler otherwise?
This is gcc 4.8.x
enum Type { A, B};
template<Type T> struct S { };
template<> struct S<A> { int x; int a; };
template<> struct S<B> { int y; int x; int b; };
template<Type T> static void foo(int x)
{
// lots of code
S<T> s;
s.x = someCall();
if (T == A)
{
s.a = 1;
}
else if (T == B)
{
s.y = 2;
s.b = 3;
}
// a bunch of common code
}
Edit: I know about making a dedicated specific functions to handle the specifics but I was hoping to avoid extra boilerplate code.
You may use specialization:
template <Type T> void bar(S<T>&);
template <> void bar(S<A>& s) {s.a = 1;}
template <> void bar(S<B>& s) {s.y = 2; s.b = 3;}
template<Type T> static void foo(int x)
{
// lots of code
S<T> s;
s.x = someCall();
bar(s);
// a bunch of common code
}
if (T == A)
[...]
else if (T == B)
[...]
A, B and T here are compile-time entities, not run-time entities. And yet you are attempting to perform a run-time evaluation of something that is known at compile time. Now sure, you could try to hack up something with a kind of iffy cast (try, and fail), or try some other kind of kludgery, but the code is telling you: you're doing it wrong.
Specializing foo is one way, as may be levarging SFINAE (as with enable_if), but from what little I can see here of your use case, that would be doing it wrong too. That's because the code you look to be implementing is some kind of initialization code, or code that manipulates the internal state of the object being used. In a sense, you're violating the principle of single responsibility.
So move that code to where the responsibility belongs: in the class that's being inited.
template<> struct S<A> { int x; int a; void init() {a=1;} };
template<> struct S<B> { int y; int x; int b; void init() { x=2; y=3; } };
template<Type T> static void foo(int x)
{
// lots of code
S<T> s;
s.x = someCall();
s.init();
// a bunch of common code
}
You could also use a factory class. This would abstract away both the instantiation of the object, and the call to init(), which can take different parameters depending on the ultimate type.

Function template parameter

I ran into the following code that defines a function template in a class:
#include <cstdint>
class foo {
public:
enum class magic_type : std::uint32_t {
START = 0,
BLUE = 0xFF000001,
RED,
};
struct header_t {
uint32_t version;
magic_type magic;
};
template <typename T>
static bool is_of_type(header_t *h)
{
return (h->magic == T::magic_type);
}
foo(uint32_t ver, foo::magic_type mag)
{
header.version = ver;
header.magic = mag;
}
header_t header;
};
I am finding the implementation of 'is_of_type` confusing. The code as is compiles, so syntactically must be correct. However, this method is not invoked from any other part of the program, so I am not sure what the intent of the function is (lack of documentation). I figured there could be two interpretation of the function:
Return true/false based on the magic type of an object and the specific enum type passed as the function template parameter.
E.g. An invocation of the method would be:
foo bar(1.2, foo::magic_type::BLUE);
bool temp = bar.is_of_type<foo::magic_type::BLUE>(&(bar.header));
However, in the above case, I am not really passing a type (as in an int, or char, etc). Right? The code does not compile.
Return true/false if the magic type is a valid enum.
In this case, I am assuming the function does not need to be templated, and could be re-written as:
static bool is_of_type(header_t *h)
{
return (h->magic == foo::magic_type);
}
E.g. of an invocation:
foo bar(1.2, foo::magic_type::BLUE);
bool temp = bar.is_of_type(&(bar.header));
Again, getting compile error. I tried using "typename", but my attempts were futile.
Can someone please help me with proper implementation of is_of_type for the above two cases and an invocation example.
The invocation would be with an explicitly specified type, which has a nested static member called magic_type.
For instance, it could be called as follows:
struct test {
static foo::magic_type const magic_type;
};
foo::magic_type const test::magic_type = 42;
foo bar{1, foo::magic_type::BLUE};
bar.is_of_type<test>(bar.header);
The fact that magic_type is used twice, once for an enum class and once for a static variable, is very confusing though.

non datatype template parameter, more specialization generated?

My Code is:
#include <iostream>
using namespace std;
template <typename T, int X>
class Test
{
private:
T container[X];
public:
void printSize();
};
template <typename T, int X>
void Test<T,X>::printSize()
{
cout <<"Container Size = "<<X <<endl;
}
int main()
{
cout << "Hello World!" << endl;
Test<int, 20> t;
Test<int, 30> t1;
t.printSize();
t1.printSize();
return 0;
}
Question:
How many specialization will get generated?.
If I understand correctly , it generates two specializations one is for <int, 20> and another is for <int, 30>. Kindly Correct if my understanding is wrong?
Is there any way to see/check the number of specializations generated by any reverse engineering?
There are not specializations here, only instantiations (this questions explains the difference). This code generates two instantiations of the class template Test.
1) yes, two instantiations will be generated by the compiler, but the linker might merge functions with identical generated code (using whole program optimization e.g.), which is a cute way to reduce code bloat.
2) see this question where it is explained how gcc can generate template instantiation output.
a) There are 2 instances of specialization get created in your example.
b)There is no builtin method to support number of specialization generated for a class.
If its your project you can add static count.
If you want you can write your own reference count mechanism for your class.
Increment static count in our constructor.
static int created = 0;
static int alive = 0;
class Test
{
counter()
{
created++;
alive++;
}
~counter()
{
created--;
}
//Rest of class
};