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])
Related
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
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);
}
#include <iostream>
using namespace std;
template<typename T>
void fun(const T & val)
{
cout << " T " << endl;
}
template<>
void fun<int>(const int & val)
{
cout << " specialization same code " << val << endl;
}
template<>
void fun<double>(const double& val)
{
cout << " specialization same code " << val << endl;
}
int main()
{
fun( 1 );
fun( 1.0 );
fun( 'c' );
return 0;
}
Question> Is there a way that I can reuse the function specialization code?
For example, assume both 'int and 'double' specialization has the exactly same implementation code. Is there a method I can prevent the code duplication?
http://codepad.org/awGYWiWv
Thank you
As suggested by #0x499602D2 in the comments, create another function and make sure it gets called only for int or double.
template<typename T>
void bar(const T & val)
{
// Make sure this gets called only for int or double.
static_assert(std::is_same<T, int>::value || std::is_same<T, double>::value);
// Do useful stuff with val.
}
template<>
void fun<int>(const int & val)
{
bar(val);
}
template<>
void fun<double>(const double& val)
{
bar(val);
}
To reuse the same code for multiple types of the same kind, you could use std::enable_if (or boost::enable_if if you are not using C++11) with type traits (a nice example is here).
e.g.:
template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, T>::type
fun(const T& val)
{
cout << " floating point specialisation " << val << endl;
}
(function specialisations of this kind work only in C++11, but you can use a struct or class for the same purpose in older C++ versions)
something like this should give you the level of re-use you want:
#include <iostream>
#include <type_traits>
using namespace std;
// will only compile if T is an arithmetic type
template<typename T,
typename std::enable_if<
std::is_arithmetic<T>::value>::type* = nullptr>
void fun(T val)
{
cout << "the square is " << val * val << endl;
}
int main()
{
int x = 10;
double y = 10;
fun(x);
fun(y);
return 0;
}
I would like to discern between static arrays and pointers.
The following example fails to compile due to array-to-pointer conversions having exact match, making both foo's possible candidates.
Am I able to get the 2nd overload of foo to be unambiguously selected using type traits?
#include <iostream>
template<typename T>
void foo(const T* str)
{
std::cout << "ptr: " << str << std::endl;
}
template<typename T, size_t N>
void foo(const T (&str)[N])
{
std::cout << "arr: " << str << std::endl;
}
int main()
{
foo("hello world"); // I would like the array version to be selected
return 0;
}
You may use the following:
namespace detail
{
template <typename T> struct foo;
template <typename T>
struct foo<T*>
{
void operator()(const T* str) {std::cout << "ptr: " << str << std::endl;}
};
template <typename T, std::size_t N>
struct foo<T [N]>
{
void operator()(const T (&str)[N]) {std::cout << "arr: " << str << std::endl;}
};
}
template<typename T>
void foo(const T& t)
{
detail::template foo<T>()(t);
}
Live example
template<typename T>
typename std::enable_if<std::is_pointer<T>::value,void>::type
foo(const T str)
{
std::cout << "ptr: " << str << std::endl;
}
template<typename T, size_t N>
void
foo(const T (&str)[N])
{
std::cout << "arr: " << str << std::endl;
}