Combining templates and type safety - c++

Let's say I have several functions defined like this:
template <typename T>
inline void read<bool>(T **data) {
//some code
}
template <typename T>
inline void read<double>(T **data) {
//some other code
}
template <typename T>
inline void read<int>(T **data) {
//also different code
}
Now, I create another function defined like this:
template<typename T>
inline void readMultiple(T **data, int counter) {
for (int i = 0; i < counter, ++i) {
read<T>(data);
}
}
(1)That would call the appropriate read<T>(T **data) implementation based on the type T, right?
(2)If I were to specify a type that is not one of the three above, I'd get a compilation error, since that function is not defined, right?
(3)Also, can I make this call:
double **d;
read<double>(d);
to ensure that I called the implementation for double?
I know I'd get the same result without the <double> part, but this way I'm ensuring that double is passed to the function, where as doing it without <double> would allow for d to be a int or a bool and the code would still compile, silently introducing an error.

(1)That would call the appropriate read<T>(T **data) implementation based on the type T, right?
Yes, assuming the specializations are visible at the point where read<T>(data) is encountered.
(2)If I were to specify a type that is not one of the three above, I'd get a compilation error, since that function is not defined, right?
You haven't provided your declaration of the template read() function, so this can't be answered. Assuming that you have declared it like template <typename T> void read(T**); and have not defined it anywhere then yes, you would get a link-time error when the linker is unable to find an implementation of the requested specialization.
(3)Also, can I make this call:
double **d;
read<double>(d);
to ensure that I called the implementation for double?
You can, though <double> is superfluous and will be inferred.
... silently introducing an error.
If the thing you're passing is a bool** then it would not be an error to use the bool specialization. I don't really see any benefit from explicitly providing the template arguments. If bool** is the wrong type then presumably you would be getting errors somewhere else, anyway.
I guess it depends on what you mean by "silently introducing an error." It's not clear what kind of error you're trying to prevent. I can come up with a contrived example, but contrived examples rarely represent real-world dangers.
Two side notes:
The syntax for your specializations is incorrect. It should be template <> inline void read<bool>(bool **data) { /* ... */ } for example.
There's no need for templates here at all, you can just have three function overloads. Having an undefined template function with explicit specializations is an anti-pattern; overloads are the recommended way to implement the same thing.

Related

Can I put static_assert in class method if I never call this method?

This version doesn't compile at all:
struct A {
void foo() {
static_assert(0,"Fail");
}
};
This version compiles without errors (at least in my version of compiler):
template <int x>
struct B {
void foo() {
static_assert(x,"Fail");
}
};
B<0> b;
The second version fails to compile only when I call b.foo();, so I want to know is it permitted by the standard to use the second version if I never call method foo? Will all compilers behave in the same way? Isn't it undefined behavior?
I want to include static_assert in the code to forbid usage of some methods of a template class when some template parameters meet some criteria. Is it correct usage of static_assert?
I want to use this approach (I want to forbid usage of .z() when vector has only two dimensions) in this situation:
template <typename T, int D>
struct MyVecctor {
MyVecctor() : data({})
{}
template <typename... Args>
MyVecctor(Args... args) : data({args...})
{
static_assert(D > 0);
static_assert(sizeof...(args) == D);
}
T& operator[] (std::size_t index) {
return data[index];
}
T& x() {
static_assert(D>=1);
return data[0];
}
T& y() {
static_assert(D>=2);
return data[1];
}
T& z() {
static_assert(D>=3);
return data[2];
}
std::array<T, D> data;
};
The behavior here is well-defined. The significant difference here is that in second case result of static_assert depends on template parameter so it won't be resolved until this method is instantiated. If it didn't depend on template parameter then it would fail just like in first case without instantiating anything:
template <int x>
struct B {
void foo() {
static_assert(0,"Fail");
}
};
And yes, forbidding usage of some methods of a template class when some template parameters met some criteria is a correct usage of static_assert. And I would even say this is a preferred method of prohibiting method because it may yield a more readable error message (even with a potential fix suggestion) compared to usual template instantiation failure gibberish.
The bodies of a template class's methods are not instantiated unless called.
However, if we consider the instantiation of bodies of a template class's methods to be template instantiations (this is unclear in the standard), then there must be a valid set of template arguments that makes the body possible to instantiate; otherwise the program is ill-formed, no diagnostic required.
In your specific case, static_assert(x, "Fail") clearly has a valid instantiation (any x!=0). So you are safe.
However
void foo() {
static_assert(x&&!x, "Fail");
}
isn't going to be safe; by my reading, that is an ill-formed program with no diagnostic required. On the other hand, my reading might be wrong; the standard is pretty oblique here.
The philosophical reason why the above is wrong is that it permits compilers to detect for impossible assumptions in static asserts; it lets the compiler check more things in the bodies of templates than the standard demands, which is I believe why the standard makes uninstantable templates ill-formed, and no diagnostic requried is because they don't want to have to force every compiler to do every kind of diagnostic for every kind of uninstantiable template (which requires solving Halt).
So philosphically, your static_asserts in non-template methods should be possible to pass for some template arguments passed to the containing template class.
Things get murkier when you have a template method to a template class which is impossible to instantiate for certain template arguments to the template class. But that is going down a rabbit hole.
I am sufficiently uncertain about that last case that I avoid doing it, and instead use CRTP to conditionally have the method exist or not.
With C++2a, you might use requires:
void foo() requires (x != 0)
{
/*..*/
}
Demo
Static Assertion static_assert(bool_constexpr, message) performs compile-time assertion checking.
If bool_constexpr returns true, this declaration has no effect.
Otherwise a compile-time error is issued, and the text of message, if
any, is included in the diagnostic message.
Your code is static_assert(0,"Fail") Because of that 0 it will assert. But, if the bool expresion depends on a template parameter (or a function parameter), it has no value at compile time (unless you use a default value), and can not assert.
static_assert(x,"Fail") may assert if the compiler knows that x= false. Using B<0> b is not enough for the compiler. The assertion is done inside foo(). If this member is used, which means that this member function is instantiated, then the compiler does assert.
Can I put static_assert in class method if I never call this method?
A static assert declaration may appear at namespace and block scope
(as a block declaration) and inside a class body (as a member
declaration)
So, yes, you can.

Why template functions do not show up in the LLVM-IR?

Why template functions do not show in the LLVM-IR if the function is not called, when emitting LLVM IR from a c++ code,
unlike other types of functions (int, float...) which will be present in the llvm ir
example: the following function func1 doesnt show in llvm ir
template <class tmp>
tmp func1 () {
// ...
}
But this function func2 always shows in llvm ir
int func2 () {
// ...
}
This is because your templates are not functions: they are function templates. They are not compiled until it is instantiated with arguments. For example, take this code:
template<typename T>
T foo() { /* ... */ }
That will nor output any code.
But this on the other hand:
template<typename T>
T foo() { /* ... */ }
int test() {
return foo<int>();
}
Will output the code for both test and foo<int>.
You can also manually instantiate a template like this:
template int foo<int>();
This has to do with how C++ templates work. Since the compiler doesn’t know what tmp is until you call the function (or more precisely, when you instantiate it), it doesn’t know how to write code for it. For example, consider this template:
template <typename T>
T add(T left, T right) {
return left + right;
}
If T is an integer, then the function body is an integer add. If T's a double, it’s a floating-point add. If T’s a std::string, it’s a function call to std::string::operator+.
Since there are a lot of types in any C++ program, and many of them can be added, and pretty much every one is added in different ways, it cannot create the code for the function until it knows this type. If it tried to do it for all possible types T, you’d get a combinatorial explosion of possible implementations, almost all of which are never used. Your compile time and binary size would be huge for little if any benefit.
Things get slightly more complicated with class templates. An instantiation of a class template doesn’t actually need to instantiate all the functions if they aren’t called. Going back to our example, if we instead wrote:
template <typename T>
class Adder {
T add(T left, T right) {
return left + right;
}
};
Adder<int> a;
this still wouldn’t instantiate Adder<int>::add even though the compiler has all the information to know that add<int> is potentially interesting, because you don’t actually call or otherwise instantiate it.

Could this templated syntax be improved?

I have this template method:
template <class SomeLhs, class SomeRhs,
ResultType (SomeLhs::*callback)(SomeRhs&)>
void Add() {
struct Local {
static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs) {
return (static_cast<SomeLhs&>(lhs).*callback)(static_cast<SomeRhs&>(rhs));
}
};
_back_end.template Add<SomeLhs,SomeRhs>(&Local::Trampoline);
}
Currently I'm calling it like this:
tracker.Add<Quad, Multi, &Quad::track>();
tracker.Add<Quad, Singl, &Quad::track>();
tracker.Add<Sext, Multi, &Sext::track>();
...
It is working fine, but I don't like to have to repeat two times the name of class SomeLhs. Is there a way to avoid that?
For people who may have recognized it: yes, this is related to the BasicFastDispatcher of Alexandrescu, in particular I'm writing a front end to operate with member functions.
I don't think it can't be improved particularly, which is unfortunate as I'd love to find a way to do this.
Template type deduction is only possible for function template arguments and you need to pass in the non-type member function pointer at compile time in order for it to be treated as a name rather than a varying quantity. Which means having to specify all the args.
i.e. you can do this:
template <class SomeLhs, class SomeRhs>
void Add(ResultType (SomeLhs::*callback)(SomeRhs&)) {
...
}
// nice syntax:
tracker.Add(&Sext::track);
// But ugly for overloaded functions, a cast is needed.
// p.s. not sure this is exactly the right syntax without compiling it.
tracker.Add((ResultType (Quad::*)(Multi&) &Quad::track);
But then you have an actual pointer that cannot subsequently be used as a template parameter.
The only thing I think you could do is to use a macro, though it is arguable if it really improves syntax here. I'd say it probably adds an unnecessary level of obfuscation.
e.g.
#define TMFN_ARGS(C, M, P1) C, P1, &C::M
tracker.Add<TMFN_ARGS(Quad, track, Multi)>();
EDIT:
However, if the name of the function is Always 'track', you could do something along the following lines:
template <typename C, typename P1>
void AddTrack() {
Add<C, P1, &C::track>();
}
tracker.AddTrack<Quad, Multi>();

Can instantiation of a template lead to a binary code duplication, does compiler prevent it?

Suppose, we declare the template:
template <class functor, int index>
class MyClass
{
public:
MyClass(){someFunction(index);}
private:
void someFunction(int index)
{
while(index--)
functor();
}
int commonFunction(void)
{
return M_PI;
}
};
Pay attention that the method commonFunction doesn`t depend on the template parameters.
Client uses this template:
MyClass<func1,100> t1;
MyClass<func2,100> t2;
// ...
MyClass<funci,100> ti;
// where i, for example in 1 .. 1000
Will instantiation of the template lead to the duplication of commonFunction in the binary code?
Can a compiler prevent that duplication?
Does C++ standart defines that duplication can be prevented, so every compiler should provide optimization?
Of course this can be easily solved by implementing common functionality for all templates in a base class and moving differences in the templated class, like this:
class baseMyClass
{
int commonFunction(void)
{
return M_PI;
}
};
template <class functor, int index>
class MyClass : private baseMyClass
{
public:
MyClass(){someFunction(index);}
private:
void someFunction(int index)
{
while(index--)
functor();
}
};
But the purpose of my question is to find out:
Does standart defines that in the cases that look like the one I gave optimization should be performed, so we can simply use template and rely on a compiler?
Does standart defines that in the cases that look like the one I gave optimization should be performed, so we can simply use template and rely on a compiler?
No, the Standard does not require by any means that conforming compilers perform such kind of optimization. Code bloating is known to be one of the drawbacks of templates.
This said, since your function does not do anything else than returning a constant, it will probably be inlined, and even in case it will not be inlined, it is possible that the linker will recognize that several identical instantiations of that function have been generated, and merge them all.
However, this behavior is not mandated by the Standard.
The standard does not mandate optimisation on any case. So the answer to your last question is no for any case you can think of. Now, the standard does not prevent optimisation either in this case, and I guess many compilers will be smart enough to do it in this simple case.

Any way to determine if class implements operator()

I'm trying to find is there's a way to check if a class is a functional because i want to write a template which uses it?
Is there an easy way to do this? Or do I just wrap things in a try/catch? Or perhaps the compiler won't even let me do it?
If you have a function template written like:
template <typename T>
void f(T x)
{
x();
}
you will be unable to instantiate it with any type that is not callable as a function taking no arguments (e.g., a class type that overloads operator() taking no arguments is callable as a function that takes no arguments). You would get a compilation error if you tried to do so.
This is the simplest way to require the type with which a template is instantiated to have certain properties: just rely on the type having those properties when you write the template, and if the type doesn't have one of the required properties, it will be impossible to instantiate the template with that type.
There are quite a few ways a parameter type can be applicable to the call syntax
Type is a pointer or reference to a function type, or
Type is a class-type which has a conversion function to one of the types in 1., or has an applicable operator().
The current C++ cannot check for 2., so you are left without checking, like the other answers explain.
This would fall under doing it and getting a compiling error. When the code is compiled the template function or template classes are are expanded for the types used as if there were duplicate copies of that template code, one for each type.
So you can basically do whatever and as long as all the types used for your templates support it you have no problem. If they don't support it you have a compiling error and you can't run your code without fixing it.
template <typename T>
void DoIt(T a)
{
a.helloworld();//This will compile fine
return a();//This will cause a compiling error if T is B
}
class A
{
public:
void a.helloworld(){}
void operator()(){}
};
class B
{
public:
void a.helloworld(){}
};
int main(int argc, char**argv)
{
A a;
B b;
DoIt(a);
DoIt(b);//Compiling error
return 0;
}
If you actually need a test to see if type T implements an operator() of some given signature then you could use the same SFINAE trick used to identify the existence of any other class member that is discussed here: C++ "if then else" template substitution