I have a trouble with next case:
template<typename T>
void test(const T &ref){
cout << "By reference";
}
template<typename T>
void test(const T *ptr){
cout << "By pointer";
}
Any parameter that I sent to the test() method will always pass to overloading with reference. Even this:
int *p = 0; test(p);
Can someone tell me why reference has so high priority and the place in standart where to read about this.
Oh... I was inattentive! I have to specify both const and non-const overloading for a pointer case:
template<typename T>
void test(const T &ref){
cout << "By reference";
}
template<typename T>
void test(T *ptr){
cout << "By pointer";
}
template<typename T>
void test(const T *ptr){
cout << "By const pointer";
}
Because const T * means that T is const but not T *.
#include <iostream>
template<typename T>
void test(const T &ref){
std::cout << "By reference\n";
}
template<typename T>
void test( T * const ptr){
std::cout << "By pointer\n";
}
int main()
{
int *p;
test(p);
return 0;
}
You can also use typedef T * PtrT, and then change T * const to const PtrT.
template <typename T>
using PtrT = T *;
template<typename T>
void test(const PtrT<T> ptr){
std::cout << "By pointer\n";
}
Can you check which type is used in template, is it int or int*? I suspect that you inspecting T to be int, but compiler interpret T as a int* and use reference template.
Try to use
test<int>(p);
to specify type explicity
Related
I have this code snipplet
template <typename T>
void p(const T* value)
{
std::cout << *value << std::endl;
}
template <typename T>
void p(const T& value)
{
std::cout << value << std::endl;
}
int main()
{
int* i = new int(5);
p(i);
}
1) According to https://cppinsights.io/ the template functions are equvilant to
template <typename T>
void p(const T* value)
{
std::cout << *value << std::endl;
}
template <typename T>
void p(const T& value)
{
std::cout << value << std::endl;
}
/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void p<int *>(int *const & value)
{
std::cout.operator<<(value).operator<<(std::endl);
}
#endif
For me this is strange. According to "Item 1 of Effective modern c++" the only case when a T can deduced as T& (or T* I guess) is when the function parameter is a universal reference (forwarding reference). However this case T is deduced as int*, but the parameter if just a pointer.
2)
If I replace
int* i = new int(5);
with
const int* i = new int(5);
This is the result
(what I expected for the first place)
template <typename T>
void p(const T* value)
{
std::cout << *value << std::endl;
}
/* First instantiated from: insights.cpp:18 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void p<int>(const int * value)
{
std::cout.operator<<(*value).operator<<(std::endl);
}
#endif
template <typename T>
void p(const T& value)
{
std::cout << value << std::endl;
}
3)
Back to 1), if I remove the overload
template <typename T>
void p(const T& value)
So I have only
template <typename T>
void p(const T* value)
{
std::cout << *value << std::endl;
}
int main()
{
int* i = new int(5);
p(i);
}
The result is
template <typename T>
void p(const T* value)
{
std::cout << *value << std::endl;
}
/* First instantiated from: insights.cpp:12 */
#ifdef INSIGHTS_USE_TEMPLATE
template<>
void p<int>(const int * value)
{
std::cout.operator<<(*value).operator<<(std::endl);
}
#endif
int main()
{
int * i = new int{5};
p(i);
}
Could you please explaint me why it is possible for T to be deduced as int* in question 1) int in question 2)?
Also I don't understand order of template argument deduction 3).
Thanks for any hints / explanations.
The implicit conversion sequence from int * to int * const & is better than the implicit conversion sequence from int * to const int *.
The latter contains a qualification conversion, and the former doesn't.
Template argument deduction is answering the question "what type do I substitute T for", not "what is the type of value". For template <typename T> void p(const T* value) that must strip a * off the argument's type.
I want to write a function which distinguish between arrays and pointers. This is needed in order to figure size of literal strings. I tried:
template<typename Ty>
void f(const Ty* rhs) {
std::cout << __FUNCTION__ << rhs << std::endl;
}
template<typename Ty, size_t Dm>
void f(const Ty(&rhs)[Dm]) {
std::cout << __FUNCTION__ << rhs << std::endl;
}
int main(int, char*[]) {
const char arr0[] = "test2";
const char* ptr = "test3";
const char arr6[6] = "test4";
f("test1");
f(arr0);
f(ptr);
f(arr6);
return 0;
}
But the compiler (VS2013) tells me that the call is ambiguous. Any hints?
Thanks in advance.
Unfortunately, the call are ambiguous.
As workaround, you may add an extra layer:
template<typename Ty>
void f_pointer(const Ty* rhs) {
std::cout << __FUNCTION__ << rhs << std::endl;
}
template<typename Ty, size_t Dm>
void f_array(const Ty(&rhs)[Dm]) {
std::cout << __FUNCTION__ << rhs << std::endl;
}
template<typename T>
std::enable_if_t<std::is_array<T>::value>
f(const T&t)
{
f_array(t);
}
template<typename T>
std::enable_if_t<!std::is_array<T>::value>
f(const T&t)
{
f_pointer(t);
}
Live Demo
An alternative to Jarod42's answer (which works) is to use class template specialization:
#include <iostream>
#include <type_traits>
template <typename T, bool is_array>
struct f_helper {
static void print_type (T& arg) {
std::cout << arg << " is an array\n";
}
};
template <typename T>
struct f_helper<T, false> {
static void print_type (T arg) {
std::cout << arg << " is not an array\n";
}
};
template <typename T>
void f (T& arg) {
f_helper<T, std::is_array<T>::value>::print_type (arg);
}
int main(int, char*[]) {
const char arr0[] = "test2";
const char* ptr = "test3";
const char arr6[6] = "test4";
f("test1");
f(arr0);
f(ptr);
f(arr6);
return 0;
}
Live demo
Change the reference to a pointer in the second overload of the function template:
template<typename T, size_t S> void f(T(&)[S]){
cout << "array with size " << S << "\n";
}
template <typename T> void f(T*&) {
cout << "pointer \n";
}
Live Demo
I don't believe it's possible to do what you're trying the way you're trying. The following statements evaluate to the same thing:
int* var
int var[]
It's all a matter of syntax sugar. Moreover, adding a size to the array on the function header has only the benefit of warning the user of the expected array size. Therefore the two are also equivalent (as far as the compiler is concerned):
void f(int* v)
void f(int v[8])
I'm looking for a solution for the following problem: I have a class in which I want to overload an operator (in this example &) for all types of pointers and for all types of arrays. Inside the implementation for arrays I need to have access to the arraysize and inside the implementation for pointers I must be able to do something with the dereferenced object.
As pointed out here, the way for the arrays is quite clear:
template<typename T, unsigned int N>
void operator&(T (&arr)[N])
{
cout << "general array operator: " << N << "\r\n";
}
But for the pointers neither of the following works:
// if I use this, the operator gets ambigous for arrays
template<typename T>
inline void operator&(T* p)
{
cout << "general pointer operator: " << (*p) << "\r\n";
}
// this doesn't work because one cannot dereference void*
void operator&(void* p)
{
cout << "general pointer operator\r\n";
(*this) & (*p);
}
Is there any good and clean solution to achieve different behaviour of an operator for arbitrary arrays and arbitrary pointers?
Here is a complete example code:
#include <iostream>
struct Class
{
template<typename T>
void operator&(T* p)
{
std::cout << "general pointer operator" << (*p) << std::endl;
}
template<typename T, unsigned int N>
void operator&(T (&arr)[N])
{
std::cout << "general array operator" << N << std::endl;
}
};
int main()
{
int myarr[5];
int* p = myarr;
Class obj;
obj & myarr; // error: operator is ambigous
obj & p; // works
return 0;
}
I have to admit that I have no idea why your snippet fails to compile properly. Anyway, a good old tag dispatching workaround seems to be working.
class cClass
{
public:
template<class T, size_t N>
void impl(T (&x)[N], std::true_type)
{
cout << "general array operator" << N << '\n';
}
template<typename T>
void impl(T* p, std::false_type)
{
cout << "general pointer operator" << (*p) << '\n';
}
template<typename T>
void operator&(T && x)
{
impl( std::forward<T>(x), std::is_array< typename std::remove_reference<T>::type >() );
}
};
The solution that changes the least code is:
template<typename T>
void operator&(T*const& p)
which gets rid of the ambiguity. I'd go with tag dispatching myself.
A C++98 solution is to have the pointer-taking operator take a const reference to a pointer.
#include <iostream>
struct Class
{
template<typename T>
void operator&(T* const &p)
{
std::cout << "general pointer operator " << (*p) << std::endl;
}
template<typename T, unsigned int N>
void operator&(T (&)[N])
{
std::cout << "general array operator " << N << std::endl;
}
};
int main()
{
int myarr[1] = { 2 };
int* p = myarr;
Class obj;
obj & myarr;
obj & p;
return 0;
}
Output:
general array operator 1
general pointer operator 2
As one example of a broader problem, given these two overloads, you might think that the array version would take priority when an array is passed:
template <size_t N>
void bar(const char (&)[N]) {
std::cout << "array, size=" << N-1 << std::endl;
}
void bar(const char *s) {
std::cout << "raw, size=" << strlen(s) << std::endl;
}
but when passing an array (a string literal is an array), bar("hello"), the latter version (the pointer version) will be called instead.
This particular case has been discussed on SO, and the answer is interesting. But there is a general question here. I want to force the compiler to prefer one overload, and to only abandon that overload only when all legal attempts to call it have failed.
Let's rename them to bar1 and bar2 for clarity:
template <size_t N>
void bar1(const char (&)[N]) {
std::cout << "array, size=" << N-1 << std::endl;
}
void bar2(const char *s) {
std::cout << "raw, size=" << strlen(s) << std::endl;
}
Without changing those any further, can we write something like this:
template<typename ...Args>
auto try_bar1_then_bar2(Args&& ...args) -> ??? {
... will first attempt to perfect forward to bar1 ...
... only if bar1 cannot be called, fallback to bar2 ...
}
I've used some C++11 in this question, with && for perfect forwarding, but I guess the general question applies to earlier C++ also. Is there a simple, general, way to force a reordering of the overload priority? When a set of functions (with different names?) are (barely) callable, how to control exactly what order they are attempted in?
Some Expression SFINAE:
template<typename ...Args>
auto try_bar1_then_bar2_IMPL(int, Args&& ...args) -> decltype( bar1(forward<Args>(args)...) ) {
cout << "Yes, we can call bar1" << endl;
return bar1(forward<Args>(args)...);
}
template<typename ...Args>
auto try_bar1_then_bar2_IMPL(char, Args&& ...args) -> void {
cout << "No, can't call bar1, calling bar2 instead." << endl;
return bar2(forward<Args>(args)...);
}
template<typename ...Args>
auto try_bar1_then_bar2(Args&& ...args) -> decltype( try_bar1_then_bar2_IMPL(0, forward<Args>(args)...) ) {
return try_bar1_then_bar2_IMPL(0, forward<Args>(args)...);
}
When bar1 cannot be called, the first overload of try_bar1_then_bar2_IMPL is invalid because the decltype in the return type fails. But if bar1 can be called, then both are valid (and are perfectly matched, I think). I've therefore added a dummy parameter in front, an int or char, which tie breaks in favour of the call to bar1.
This is called like so:
try_bar1_then_bar2("hello"); // array, calls array version
try_bar1_then_bar2(+"hello"); // + converts to a pointer, therefore
// this calls the pointer ('raw') version.
You can wrap the arguments with a template to get the desired overloaded function:
#include <cstring>
#include <iostream>
template <typename T>
struct Wrap
{
const T& value;
Wrap(const T& value)
: value(value)
{}
};
template <typename T>
inline Wrap<T> wrap(const T& value) {
return Wrap<T>(value);
}
template <size_t N>
void bar(const Wrap<char[N]>&) {
std::cout << "array, size=" << N-1 << std::endl;
}
void bar(const Wrap<const char *>& s) {
std::cout << "raw, size=" << strlen(s.value) << std::endl;
}
template <typename T>
void bar(const T& value) {
bar(wrap(value));
}
int main(int argc, char* argv[]) {
const char a[] ="hello";
const char* s ="hello";
bar(a);
bar(s);
}
I want to overload two functions based on whether the argument is a temporary object, so I write code like this:
#include <iostream>
void f(int &&)
{
std::cout << "&&" << std::endl;
}
void f(const int&)
{
std::cout << "const &" << std::endl;
}
int main()
{
int i;
f(i);
f(i + 1);
}
And it corrently output:
const &
&&
However, when I change the code to use template like this:
#include <iostream>
template <typename T>
void f(T &&)
{
std::cout << "&&" << std::endl;
}
template <typename T>
void f(const T&)
{
std::cout << "const &" << std::endl;
}
int main()
{
int i;
f(i);
f(i + 1);
}
The output becomes:
&&
&&
What's the problem? How can I optimize for moveable temporary object when using template?
edit:
Actually, this is a test code when I read C++ Primer. It says:
template <typename T> void f(T&&); // binds to nonconst rvalues
template <typename T> void f(const T&); // lvalues and const rvalues
After my experiment, it seems the book makes a mistake here.
template <typename T>
void f(T &&)
{
std::cout << "&&" << std::endl;
}
Uses universal forwarding reference and allows any types with reference collapsing.
You have to use T with a no deducing context as wrapping your code into a struct:
template <typename T>
struct helper
{
void f(T &&)
{
std::cout << "&&" << std::endl;
}
void f(const T&)
{
std::cout << "const &" << std::endl;
}
};
template <typename T>
void f(T &&t)
{
helper<typename std::decay<T>::type>().f(std::forward<T>(t));
}
Live example