# Questions about Templates

## Recommended Posts

I was doing an experiment, code below:

template<typename T>
struct S
{
explicit S(T v) :val{ v } {};
T val;
};

int main()
{
S<int> MyS('g');
cout << MyS.val << endl;//Output is 103

return 0;
}

Even though I am providing T with a type which is int, and I have an explicit constructor, why I have an implicit conversion from char to int? Shouldn't it see that T is int since I'm telling it so and thus give me error for constructing an S out of char?

Edited by MarcusAseth

##### Share on other sites

The explicit keyword means that it won't create an instance of the object without you explicitly constructing one - for example, as part of an expression where it might normally make sense to the compiler to cast some object to this type, but where you want to disallow this.

Here, you do explicitly construct an object of the type, so it calls the constructor, and it makes the normal effort to convert the argument for you.

In this example, it's the 'int' that has an 'implicit' or 'converting' constructor, which magically creates an int out of a char. You don't get to change the semantics of ints, though.

To recap: explicit constructors don't say anything about their arguments, they say things about when they can be legitimately called.

##### Share on other sites

Thanks @Kylotan, I had grossly misunderstood the meaning of that keyword

##### Share on other sites

Not grossly. You obviously understand the basic concept, of avoiding the implicit conversion, but you were just unsure which 'end' of the process it applied to.

##### Share on other sites

I'm changing the title of the topic into "Questions about Templates" because I'm experimenting with it and I know I will have more than one, doesn't seems right to make 1000 mini-topics

So now I have the code below:

template<typename T>
struct S
{
S(T v) :val{ v } {};
T val;
};

template <typename R, typename T>
R& get(T& e)
{
return e.val;
}

int main()
{
S<char> MySChar('B');
cout << "MySChar: " << MySChar.val << endl;

cout << "Returned val: " << get<char>(MySChar) << endl;

return 0;
}

The function get is not part of the S class, as required from the book exercise (which is "" Add a function template get() that returns a reference to val.")

I don't like that I have to specify the return type when I call it, if I have 5 different instantiation of S it becomes messy, so I was trying to make it in such a way that I can just write get(MySChar) and it just works with wathever instantiation of S, but I am failing on it, code below:

template<typename T>
struct S
{
S(T v) :val{ v } {};
T val;
typedef T type;
};

template <typename T, typename R>
R& get(T& e)
{
using R = e.type;
return e.val;
}

int main()
{
S<char> MySChar('B');

cout << "MySChar: " << MySChar.val << endl;

cout << "Returned val: " << get(MySChar) << endl;

return 0;
}

How would I do that the proper way?

##### Share on other sites
47 minutes ago, MarcusAseth said:

I was doing an experiment, code below:


template<typename T>
struct S
{
explicit S(T v) :val{ v } {};
T val;
};

int main()
{
S<int> MyS('g');
cout << MyS.val << endl;//Output is 103

return 0;
}

Even though I am providing T with a type which is int, and I have an explicit constructor, why I have an implicit conversion from char to int? Shouldn't it see that T is int since I'm telling it so and thus give me error for constructing an S out of char?

In C++ words, this is called promotion. Promotions happen automatically.

See for example Integral promotion of this page.

##### Share on other sites

Well, I kind of found a solution to my last question (by throwing everything at random at it), which is auto& return type. But still out of curiosity, what would be the second best alternative to auto, using templates?

template <typename T>
auto& get(T& e)
{
return e.val;
}

Edited by MarcusAseth

##### Share on other sites

You're probably looking for the decltype keyword, but this is all too abstract for me to even work out what you're trying to do at a glance.

##### Share on other sites
15 minutes ago, Kylotan said:

but this is all too abstract for me to even work out what you're trying to do at a glance.

nothing too fancy, I'm just trying to make the code below compile without changing it but just by modifying that get() function

The code below the commented line that says "//THIS 5 LINES BELOW NEEDS TO COMPILE"

int main()
{
S<int> MySInt(5);
S<char> MySChar('B');
S<double> MySDouble(2.2);
S<string> MySString(string("wow!"));
S<vector<int>> MySVec(vector<int>(4, 99));

cout << "MySInt: " << MySInt.val << endl;
cout << "MySChar: " << MySChar.val << endl;
cout << "MySDouble: " << MySDouble.val << endl;
cout << "MySString: " << MySString.val << endl;

cout << "MySVec: ";
for (auto& e : MySVec.val)
cout << e << " ";
cout << endl;

//THIS 5 LINES BELOW NEEDS TO COMPILE
cout << "Returned val from get(): " << get(MySInt) << endl;
cout << "Returned val from get(): " << get(MySChar) << endl;
cout << "Returned val from get(): " << get(MySDouble) << endl;
cout << "Returned val from get(): " << get(MySString) << endl;
cout << "Returned val from get(): " << get(MySVec)[0] << endl;

return 0;
}

So this is the function with decltype (assuming I am using it correctly) but doesn't work as well

template <typename T, typename R>
R& get(T& e)
{
decltype(e.val) R;
return e.val;
}

auto& as return type works just fine and those 5 lines compile, I was just wondering if there where any other ways

Edited by MarcusAseth

##### Share on other sites

Moving to a new question, why is the code below not compiling if I uncomment one of the 4 commented-out lines ?

Function "set(Container, newValue, ID)"  takes a "MyContainer" class, a new value to set and an optional ID, just in case is a MyContainer<vector<int>>.

inside of it, takes the "val" of the MyContainer which returns wathever it is containing, in the example case is indeed a vector<int>&, but as soon as I try to use an operator<< or operator= on Vec, this thing doesn't compile...what am I not getting here?

template<typename T>
struct is_Container {
static const bool value = false;
};

template<typename T, typename Alloc>
struct is_Container<vector<T,Alloc>> {
static const bool value = true;
};

template <typename T, typename V>
void set(MyContainer<T>& e, V newVal, int ID = 0)
{
T& Val = e.get();
if (is_Container<T>::value)
{
cout << "is a vector" << endl;
//cout << Val[ID] << endl;
//Val[ID] = newVal;
}
else
{
cout << "is not a container" << endl;
//cout << Val << endl;
//Val = newVal;
}
}

Edited by MarcusAseth

##### Share on other sites

When you say something is "not compiling", it's normally polite to give the error message. That usually tells you everything you need to know...

##### Share on other sites
14 minutes ago, Kylotan said:

When you say something is "not compiling", it's normally polite to give the error message. That usually tells you everything you need to know...

Good point, I didn't yet sorted out the problem of my VC being in Italian, but I'll paste the error link

I'm getting 2 Compiler Error C2109 on line 52 and 53 where I try to  use Val[ID] inside my "if" block

Quote

subscript requires array or pointer type

And 2 Compiler Error C2679 on line 58 and 59 where I try to use Val inside my "else" block

Quote

binary 'operator' : no operator found which takes a right-hand operand of type 'type' (or there is no acceptable conversion)

But from the screenshot is clearly visible that Val is a vector<int>& therefore I don't get it.. well, since it doesn't run it is failing at compile time or before, so I assume this is because at that time is not known what Val will be, and is only know later on. So how do I get it to "assume" that I will provide a valid variable with those operators (operator[], operator<<, operator=) at run-time?! x_x

Edited by MarcusAseth

##### Share on other sites

Ok, trough commenting and uncommenting I think I've realized what is going on here:

template <typename T, typename V>
void set(MyContainer<T>& e, V newVal, int ID = 0)
{
T& Val = e.get();
if (is_Container<T>::value)
{
cout << "is a vector" << endl;
//cout << Val[ID] << endl;
//Val[ID] = newVal;
}
else
{
cout << "is not a container" << endl;
//cout << Val << endl;
//Val = newVal;
}
}

When set() is instantiated with a first parameter that contain a MyContainer of basic type let's say int, then T is int and the expressions

Quote

//cout << Val[ID] << endl;
//Val[ID] = newVal;

becomes totally invalid (even though the control flow would never send us there).

On the other hand when I instantiate it with a MyContainer<vector<int>> as first parameter, then the expressions

Quote

//cout << Val << endl;
//Val = newVal;

make no sense at all. (cout of vector<int> and assignment of int to vector<int>

Working with templates can be confusing, it seems

How is this situation handled? Should Val be passed down to a function template with partial specialization for vectors and non vectors? I think that would work, but can't be too sure with this stuff

Edited by MarcusAseth

##### Share on other sites

Function overloading did it, so that must be the way to go, (I hope)

This is actually cool, because I can direct the flow of things toward the no inplicit conversion function overload!

I'm discovering hot water here

template <typename T, typename V>
void set(MyContainer<T>& e, V newVal, size_t ID = 0)
{
cout << "MyContainer specialization called" << endl;
T& Val = e.get();
set(Val, newVal, ID);
}

template <typename T>
void set(vector<T>& Val, T newVal, size_t ID = 0)
{
cout << "vector specialization called" << endl;
Val[ID] = newVal;
}
template <typename T, typename V>
void set(vector<T>& Val, V newVal, size_t ID = 0)
{
cout << "NO IMPLICIT CONVERSION called" << endl;
}

template <typename T, typename V>
void set(T& Val, V newVal, size_t ID = 0)
{
cout << "base type specialization called" << endl;
Val = newVal;
}
int main()
{
MyContainer<int> MySInt(5);
MyContainer<vector<int>> MySVec(vector<int>(4, 99));

cout << "MySInt: " << get(MySInt) << endl;
set(MySInt, 22);
cout << "MySInt: " << get(MySInt) << endl << endl << endl;

cout << "MySVec: " << get(MySVec)[2] << endl;
set(MySVec, 3.3, 2);
cout << "MySVec: " << get(MySVec)[2] << endl << endl << endl;

cout << "MySVec: " << get(MySVec)[2] << endl;
set(MySVec, 64, 2);
cout << "MySVec: " << get(MySVec)[2] << endl << endl << endl;
return 0;
}

Output:

Quote

MySInt: 5
MyContainer specialization called
base type specialization called
MySInt: 22

MySVec: 99
MyContainer specialization called
NO IMPLICIT CONVERSION called
MySVec: 99

MySVec: 99
MyContainer specialization called
vector specialization called
MySVec: 64

Edited by MarcusAseth

##### Share on other sites
3 hours ago, MarcusAseth said:

S(T v) :val{ v }

I would just use the non-braced initializer list:

S(T v) :val(v)

I only use braced initializer list for zero-initializing arrays. Due to type deductions in C++11/14, braced initializer lists can be tricky.

FYI: setting up VS2017 can be cumbersome (you need lots of LMB clicks) for small C++ tests. You can use the Visual C++ compliant single header web compiler: http://webcompiler.cloudapp.net/.

Edited by matt77hias

##### Share on other sites
11 minutes ago, matt77hias said:

I would just use the non-braced initializer list:


S(T v) :val(v)

curly braces are the safest way, right?

If in there I'm initializing member variables, then { } prevents me to pass argument that would require an implicit conversion and possible truncation, so I just use those always and I never have to think about it because if I make a mistake, then things stop working right away

Edited by MarcusAseth

##### Share on other sites
9 minutes ago, MarcusAseth said:

curly braces are the safest way, right?

If in there I'm initializing member variables, then { } prevents me to pass argument that would require an implicit conversion and possible truncation, so I just use those and I never have to thing about it becuase if I make a mistake, then things stop working immediately

Safe? I guess (although in combination with std::initializer_list constructors?).

Obvious? No.

int a[3] = {1};
cout << a[0] << ',' << a[1] << ',' << a[2] << endl; 

What do you mean with the "prevention of passing arguments that would require implicit conversion"?

Edited by matt77hias

##### Share on other sites
28 minutes ago, matt77hias said:

Safe? I guess.

Obvious? No.


int a[3] = {1};
cout << a[0] << ',' << a[1] << ',' << a[2] << endl; 

Well, honestly, you example above to me seems obvious though

an array of 3 elements taking an initializer list, the initializer list to the right sets the first element to 1.

Quote

What do you mean with the "prevention of passing arguments that would require implicit conversion"?

I mean that the code below won't compile because it requires a conversion from double to int

	int a[3] = { 1.4 };
cout << a[0] << ',' << a[1] << ',' << a[2] << endl;

If you accidentally passed a float variable you would have lost precision without noticing maybe, that's why I think is valuable to prefer it to the more loose ( )

EDIT: I compiled my example just to be sure, apparently it works, I must have got it wrong from the book o_O

Need to check.

EDIT2: ok, the safety I mentioned won't apply when you use it to initialize an array it seems, but it still work on all the future uses, and I think some safety is better than no safety at all (and it comes for free, so...I'll take it!)

Edited by MarcusAseth

##### Share on other sites
1 hour ago, MarcusAseth said:

EDIT2: ok, the safety I mentioned won't apply when you use it to initialize an array it seems, but it still work on all the future uses, and I think some safety is better than no safety at all (and it comes for free, so...I'll take it!)

99% of my non-default/non-move/non-copy constructors are explicit, so except for implicit primitive-to-primitive conversions, I personally prefer calling the constructor straight away with () instead of {} (which calls a std::initializer_list constructor if present) in the constructor initializer list. Furthermore, my compiler uses the highest (reasonable, so not Wall) warning level to notify me of possible losses of precision due to for instance implicit primitive-to-primitive conversions.

Edited by matt77hias

##### Share on other sites

More template stuff.

I have some doubts regarding template, still. This compile and works, and if I understand it right, I need the operator overloads to be templates in case I try to do something like "Number<int>(3) + Number<float>(4.15)" which are two different type.

If I have those operator overloads just taking a plain Number& as argument, then things won't compile.

And yet, operator>> and operator<< just work fine with a Number&, how does that make sense?!

EDIT: while I was writing this question, I thought that maybe is because inside a particular template instantiation itself, Number is defined to be the unique type for that Number<T>, therefore by saying Number I am actually calling the unique type of that particular instantiation?

If that was the case I could then just have a  return type Number& in the operator overloads instead of return type Number<T>& , can you guys confirm this is the case?

template<typename T>
class Number {
T val;
public:
//Constructors
Number() :val{ 0 } {}
Number(T v) :val{ v } {}

//Methods
T& get() { return val; }

//Operators
template<typename U>
Number<T>& operator+(Number<U>& rhs) { val += rhs.get(); return *this; }
template<typename U>
Number<T>& operator-(Number<U>& rhs) { val -= rhs.get(); return *this; }
template<typename U>
Number<T>& operator*(Number<U>& rhs) { val *= rhs.get(); return *this; }
template<typename U>
Number<T>& operator/(Number<U>& rhs) { val /= rhs.get(); return *this; }

friend ostream& operator<<(ostream& stream, Number& rhs) { stream << rhs.val; return stream; }
friend istream& operator>>(istream& stream, Number& rhs) { stream >> rhs.val; return stream; }
};

int main()
{
Number<double> myDouble(3.4);
myDouble - Number<int>(6.6);
cout << myDouble << endl << endl;

cin >> myDouble;
cout << myDouble << endl;

return 0;
}

##### Share on other sites

Again, what are the compiler errors you get?

These operators are wrong anyway, because they are mutating the left-hand side when they should be returning a new value. If you want += semantics, you should define a += operator.

##### Share on other sites
9 minutes ago, Kylotan said:

Again, what are the compiler errors you get?

No compile errors, quoting my message above:

Quote

And yet, operator>> and operator<< just work fine with a Number&, how does that make sense?

##### Share on other sites
2 minutes ago, MarcusAseth said:

No compile errors

28 minutes ago, MarcusAseth said:

If I have those operator overloads just taking a plain Number& as argument, then things won't compile.

##### Share on other sites

@Lactose Maybe I didn't explained myself properly, I am not considering that as the error, that's why is not even in my code example, and that makes sense because as I said

Quote

I need the operator overloads to be templates in case I try to do something like "Number<int>(3) + Number<float>(4.15)" which are two different type.

In that case the compile error is obviously I have no operator overload between the 2 different types, if it was Number&.

The question is another one...and is about the absence of ant kind of compile errors

Edited by MarcusAseth

##### Share on other sites

Sorry, you're talking in hypotheticals. Can you form a smaller, precise example of the problem? i.e.

1. What are you doing?
2. What do you expect or want to happen?
3. What actually happens?

## Create an account or sign in to comment

You need to be a member in order to leave a comment

## Create an account

Sign up for a new account in our community. It's easy!

Register a new account

• 10
• 14
• 11
• 10
• 11
• ### Similar Content

• I'm having some difficulty understanding how data would flow or get inserted into a multithreaded opengl renderer where there is a thread pool and a render thread and an update thread (possibly main). My understanding is that the threadpool will continually execute jobs, assemble these and when done send them off to be rendered where I can further sort these and achieve some cheap form of statelessness. I don't want anything overly complicated, fibers job stealing etc. My end goal is to simply have my rendereer isolated in it's own thread and only concerned with drawing.
My questions are:
1. At what point in this pipeline are resources created?
Say I have a
class CCommandList { void SetVertexBuffer(...); void SetIndexBuffer(...); void SetVertexShader(...); void SetPixelShader(...); } borrowed from an existing post here. I would need to generate a VAO at some point and call glGenBuffers etc especially if I start with an empty scene. If my context lives on another thread, how do I call these commands if the command list is only supposed to be a collection of state and what command to use. I don't think that the render thread should do this and somehow add a task to the queue or am I wrong?
Or could I do some variation where I do the loading in a thread with shared context and from there generate a command that has the handle to the resources needed.

2. How do I know all my jobs are done.
I'm working with C++, is this as simple as knowing how many objects there are in the scene, for every task that gets added increment a counter and when it matches aforementioned count I signal the renderer that the command list is ready? I was thinking a condition_variable or something would suffice to alert the renderthread that work is ready.

3. Does all work come from a singular queue that the thread pool constantly cycles over?
With the notion of jobs, we are basically sending the same work repeatedly right? Do all jobs need to be added to a single persistent queue to be submitted over and over again?

4. Are resources destroyed with commands?
Likewise with initializing and assuming #3 is correct, removing an item from the scene would mean removing it from the job queue, no? Would I need to send a onetime command to the renderer to cleanup?

• So I wrote a programming language called C-Lesh to program games for my game maker Platformisis. It is a scripting language which tiles into the JavaScript game engine via a memory mapper using memory mapped I/O. Currently, I am porting the language as a standalone interpreter to be able to run on the PC and possibly other devices excluding the phone. The interpreter is being written in C++ so for those of you who are C++ fans you can see the different components implemented. Some background of the language and how to program in C-Lesh can be found here: