Is it possible to overload a function that can tell a fixed array from a pointer?
This seems to work for me
#include <iostream>
template<typename T>
std::enable_if_t<std::is_pointer<T>::value>
foo(T) { std::cout << "pointer\n"; }
template<typename T, std::size_t sz>
void foo(T(&)[sz]) { std::cout << "array\n"; }
int main()
{
char const* c;
foo(c);
foo("hello");
}
Bonus std::experimental::type_traits
:
using std::experimental::is_pointer_v;
std::enable_if_t<is_pointer_v<T>>
Your comment made me try something even simpler
template<typename T> void foo(T) { std::cout << "pointer\n"; }
template<typename T, unsigned sz> void foo(T(&)[sz]) { std::cout << "array\n"; }
Of course the problem here is that foo
is now callable for any type, depends on how lax you want your parameter checking to be.
One other way is to (ab)use rvalue references
void foo(char const*&) { std::cout << "pointer\n"; }
void foo(char const*&&) { std::cout << "array\n"; }
Obviously it's not foolproof.
c++ overload operator Dynamic and Static array
At
int * pointer;
int arr[40]={0};
pointer = arr;
pointer will be an array of 40 bytes. This array is not dynamically allocated and will be completely removed at the end of the function. Change your function to this:
int* random()
{
int * pointer = new int[40];
cout << "Random function: ";
for(int j = 0; j < 40; j++){
pointer[j] = rand()%10; cout << pointer[j];
}
cout << endl;
return pointer;
}
This way you will keep the values of pointer and you can use them in other functions.
array decay to pointer and overload resolution
You need to make the first overload a poorer choice when both are viable. Currently they are a tie on conversion ranking (both are "Exact Match"), and then the tie is broken because non-templates are preferred.
This ought to make the conversion ranking worse:
struct stg
{
struct cvt { const char* p; cvt(const char* p_p) : p(p_p) {} };
// matches const char*, but disfavored in overload ranking
stg(cvt c_str); // use c_str.p inside :( Or add an implicit conversion
template<int N>
stg(const char (&str) [N]);
};
Can I overload an operator taking a pointer and a non-constructed template object?
No. The syntax foo<...>
can only be a class (or alias) template (which is an invalid expression) or function template (which becomes a function pointer, which you can’t overload for).
Static array of const pointers to overloaded, templatized member function
To use BOOST_PP_ENUM
in the way that you've shown, you would need a macro that takes a 'number' and yields an expression that is the address of an appropriate member of the appropriate class. I don't see a good way to do this without an explicit list unless the desired functions all have manufactured names (e.g. memfun1
, memfun2
, etc.). Except in the case, it's going to be easier to list the function address expressions explicitly that to used BOOST_PP_ENUM.
You are using identifiers in this array that are the same as the template parameters in Some_class
.
R (U::* const pmfi[])(T&) = { /* ... */ }
Is this really supposed to be the templated member of Some_class?
template< class T, class U, class R >
R (U::* const Some_class<T, U, R>::pmfi[])(T&) = { /* ... */ }
If so, is the same instantiation going to work with all combinations of types that you are going to us the template Some_class
with? If so, you have a very constrained set of classes, perhaps you can do away with the template. If not, you are going to have to specialize Some_class
for every combination of template parameters in which case the template is not gaining you very much.
Edit, post edit: If I've understood you correctly then you can't do what you've suggested because the array of pointers must be of exactly the right signature.
Reducing it to a simple function pointer example, you can't do this:
void f(Derived&);
void (*p)(Base&) = &f;
otherwise, it would subvert type safety:
OtherDerived od; // derived from Base, but no from Derived
// I've managed to pass something that isn't a Derived reference to f
// without an explicit (and dangerous) cast
(*p)(od);
In your array of function pointers, the initializers must all be to functions of the right signature.
C++ overloaded method pointer
(void (A::*)()) &A::f
(void (A::*)(int)) &A::f
function pointers and member function pointers have this feature - the overload can be resolved by to what the result was assigned or cast.
If the functions are static, then you should treat them as ordinary functions:
(void (*)()) &A::f;
(void (*)(int)) &A::f;
or even
(void (*)()) A::f;
(void (*)(int)) A::f;
Overload resolution and arrays: which function should be called?
First, the conversion sequence of all three is the same, except that for the first two, there is an lvalue transformation (lvalue to rvalue conversion), which however is not used in ordering conversion sequences. All three are exact matches (the function template specialization has parameter type char const(&)[2]
).
If you iterate over the rules at 13.3.3.2p3
, you stop at this paragraph
S1 and S2 are reference bindings (8.5.3) and neither refers to an implicit object parameter of a non-static member function declared without a ref-qualifier, and S1 binds an rvalue reference to an rvalue and S2 binds an lvalue reference.
A conversion sequence cannot be formed if it requires binding an rvalue reference to an lvalue, the spec says at 13.3.3.1.4p3. If you look at how reference binding works at 8.5.3p5 last bullet, it will create a temporary (I think they meant rvalue temporary) of type char const*
from the array lvalue and bind the reference to that temporary. Therefor, I think (1)
is better than (2)
. Same holds for (1)
against (3)
, although we wouldn't need this because (3)
is a template so in a tie, we would choose (1)
again.
In n3225
, they changed the reference binding rules so that rvalue references can bind to initializer expressions that are lvalues, as long as the reference will be bound to an rvalue (possibly created by converting the initializer properly before). This could influence the handling by Visual C++, which may not be up to date here.
I'm not sure about clang. Even if it would ignore (1)
, then it would end up in a tie between (2)
and (3)
, and would need to choose (2)
because it's a non-template.
I think that 8.5.3p5 last bullet is confusing because it says "Otherwise a temporary of type ..". It's not clear whether the temporary is regarded as an lvalue or as an rvalue by 13.3.3.1.4p3, which means I'm not sure how the following should really behave according to the exact words of the spec
void f(int &);
void f(int &&);
int main() {
int n = 0;
f(n);
}
If we assume the temporary is treated as an rvalue by clause 13, then we bind an rvalue ref to an rvalue in the second function and an lvalue in the first. Therefor, we will choose the second function and then get a diagnostic by 8.5.3p5 last bullet because T1
and T2
are reference-related. If we assume the temporary is treated as an lvalue by clause 13, then the following would not work
void f(int &&);
int main() {
f(0);
}
Because we would bind an rvalue ref to an lvalue which by clause 13 will make the function non-viable. And if we interpret "binding an rvalue ref to an lvalue" to refer to the initializer expression instead of the final expression bound to, we won't accept the following
void f(float &&);
int main() {
int n = 0;
f(n);
}
This however is valid as of n3225. So there seems to be some confusion - I sent a DR to the committee about this.
Overload resolution for char*, char array, and string literals using constexpr, SFINAE and/or type_traits
Per [expr.prim.id.unqual]:
[...] The type of the expression is the type of the identifier. The
result is the entity denoted by the identifier. The expression is an
lvalue if the entity is a function, variable, or data member and a
prvalue otherwise; it is a bit-field if the identifier designates a
bit-field ([dcl.struct.bind]).
Therefore, given a declaration
const char arr[] = "foo";
The expression arr
is an lvalue of type const char[4]
.
Per [lex.string]/8:
Ordinary string literals and UTF-8 string literals are also referred
to as narrow string literals. A narrow string literal has type “array
of nconst char
”, where n is the size of the string as defined
below, and has static storage duration.
And per [expr.prim.literal]:
A litera is a primary expression. Its type depends on its form. A
string literal is an lvalue; all other literals are prvalues.
Therefore, the expression "foo"
is an lvalue of type const char[4]
.
Conclusion: a function is unable to differentiate between a (const) char array and a string literal.
Related Topics
Clean Up Your #Include Statements
C++ Linux Double Destruction of Static Variable. Linking Symbols Overlap
Is C++ Considered Weakly Typed? Why
Testing If Given Number Is Integer
C++11 Variadic Printf Performance
Comparing Two Integers Without Any Comparison
Sign Changes When Going from Int to Float and Back
Qt 5.5 Embed External Application into Qwidget
Qtcreator: No Valid Kits Found
May Volatile Be in User Defined Types to Help Writing Thread-Safe Code
C++: Nested Template Classes Error "Explicit Specialization in Non-Namespace Scope"
Qthread Emits Finished() Signal But Isrunning() Returns True and Isfinished() Returns False
Difference Between File Scope and Global Scope
How to Write an Adl-Enabled Trailing Return Type, or Noexcept Specification
How to Find the 'Temp' Directory in Linux