Questions about Templates

Started by
30 comments, last by Kylotan 6 years, 7 months ago

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? :S

 

Advertisement

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.

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

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. :)

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? :S

 

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.

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? :P


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

 

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.

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 :P 

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? :S


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;
	}
}

GcucCqV.png

This topic is closed to new replies.

Advertisement