No ADL inside decltype on VS2012 - c++

I just realized that trying to get the return type of a function via decltype does not involve ADL (argument-dependent-lookup) on VS2012 (tested using cl.exe V17.00.60610.1).
The following example
#include <stdio.h>
#include <typeinfo>
namespace A {
int Func(void const *) {
printf("A::Func(void const *)\n");
return 0;
}
template <typename T> void Do(T const &t) {
Func(&t);
}
template <typename T> void PrintType(T const &t) {
printf("Type: %s\n", typeid(decltype(Func(&t))).name());
}
}
namespace B {
struct XX { };
float Func(XX const *) {
printf("B::Func(XX const *)\n");
return 0.0f;
}
}
int main(int argc, char **argv) {
B::XX xx;
A::Do(xx);
A::PrintType(xx);
return 0;
}
Gives
B::Func(XX const *)
Type: int
on VS2012
but (what is expected):
B::Func(XX const *)
Type: f
on gcc 4.7.3.
So ADL works when calling the function (line 1 in output) but not when used inside decltype on VS2012.
Or am I missing some different point?

A minimal test case is:
namespace N
{
struct C {};
C f(C) {};
}
N::C c1;
decltype(f(c1)) c2;
If the compiler doesn't support ADL inside decltype, then the above will not compile.
I'm told it does compile, so maybe it is the interaction between ADL and template instantiation that is the problem.

If find it amusing that the IDE/Intellisense whatsoever seems to do the lookup correctly but the compiler does not.
This example shows no intellisense errors and a is displayed to be of type size_t when hovering it.
#include <iostream>
namespace A
{
struct C {};
size_t f(C*) { return 5U; };
}
namespace B
{
void f(void *) { };
void f2 (A::C x)
{ decltype(f(&x)) a; std::cout << typeid(a).name() << std::endl; }
}
int main (void)
{
A::C c;
B::f2(c);
}
The compiler stops with Error C2182 and complains about a variable of type void.
It seems to be a problem independant of templates.

Related

Make int overload a preferable one

Consider following code snippet:
class Foo {
public:
void bar(std::size_t){}
void bar(const char* ){}
};
int main() {
auto foo = Foo{};
foo.bar(0);
}
It produces ambiguous calls errors (check here). But I think from programmer's perspective it is pretty obvious that I want to call overload with std::size_t. My question is if anything can be done so this code does not produce errors and calls size_t overload?
can be done like this in C++ 20
#include <cstdint>
#include <iostream>
#include <type_traits>
class Foo {
public:
template <typename T>
requires std::is_integral_v<T>
void bar(T){
std::cout<<"hello size_T";
}
void bar(const char* ){
std::cout<<"hello";
}
};
int main() {
auto foo = Foo{};
foo.bar(25);
}
In modern c++ (at least c++17), we prefer to pass string_view as argument over const char* for the none owner transfer cases, so a considerable choice:
#include <cctype>
#include <string>
class Foo {
public:
void bar(std::size_t){}
void bar(std::string_view){}
};
int main() {
auto foo = Foo{};
foo.bar(0);
}
Online demo
In below C++ 20, this works well.
#include <iostream>
class Foo {
public:
template <typename T>
void bar(T) {
std::cout << "hello T" << std::endl;
}
void bar(const char* c) {
std::cout << c << std::endl;
}
};
int main() {
auto foo = Foo{};
foo.bar(0);
foo.bar("test.");
}
This works in C++23:
foo.bar(0zu);
and this works pre-C++23:
foo.bar(size_t{0});

Using functions in a namespace that hasn't been declared from template

The following code give me an error that 'print2' is not a member of 'N' when using both clang and gcc:
#include <stdio.h>
struct Printer
{
template<class T>
void print(T t)
{
N::print2(*this, t);
}
};
namespace N
{
void print2(Printer& p, int v)
{
printf("%d\n", v);
}
}
int main()
{
Printer p;
p.print(1);
}
If I remove the namespace N and make the print2 function global it works. Why is the lookup different when the function is put in a namespace and when it's not? Unfortunately I can't move the print2 function before struct Printer, which would've been the obvious solution.
Here I am simply declaring the function before Printer, while defining the logic of the function afterwards.
#include <stdio.h>
namespace N {
void print2(int);
}
struct Printer
{
template<class T>
void print(T t)
{
N::print2(t);
}
};
namespace N
{
void print2(int v)
{
printf("%d\n", v);
}
}
int main()
{
Printer p;
p.print(1);
}

C2440 cannot convert from 'void (_cdecl*)(int)' to 'void(_cdecl&)(int)

I am using C++ in native mode with Visual Studio 2017 and I am trying to compile and run the example code found at Debugging a Parallel Application in Visual Studio.
For the record, I program in C not C++. I am clueless when it comes to method declarations (among many other things). I suspect correcting the error is simple but, I simply don't know how.
In other words, I am currently RTFineM. I simply copied and pasted the example given in the url above and ran into 2 problems. First it complained about something being deprecated but a simple define took care of that problem. Second it complained about not being able to convert a type into another as stated in the title.
The RunFunc class causing the problem is declared as follows:
class RunFunc
{
Func& m_Func;
int m_o;
public:
RunFunc(Func func,int o):m_Func(func),m_o(o)
{
};
void operator()()const
{
m_Func(m_o);
};
};
My question/request is: how does the declaration of RunFunc need to be in order for the example to compile and run properly ?
Thank you, much appreciate the help.
In this constructor
RunFunc(Func func,int o):m_Func(func),m_o(o)
{
};
the prameter Func func is adjusted by the compiler to the type Func *func. On the other hand the data member m_Func is declared as a referenced type.
Func& m_Func;
And the error message says about incompatibility of the types.
C2440 cannot convert from 'void (_cdecl*)(int)' to 'void(_cdecl&)(int)
Try to declare the constructor like
RunFunc(Func &func,int o):m_Func(func),m_o(o)
{
};
Or declare the data member like
Func *m_Func;
without changing the constructor.
Here are two demonstrative programs
#include <iostream>
typedef void Func( int );
class RunFunc
{
Func& m_Func;
int m_o;
public:
RunFunc(Func &func,int o):m_Func(func),m_o(o)
{
};
void operator()()const
{
m_Func(m_o);
};
};
int main() {
return 0;
}
and
#include <iostream>
typedef void Func( int );
class RunFunc
{
Func *m_Func;
int m_o;
public:
RunFunc(Func func,int o):m_Func(func),m_o(o)
{
};
void operator()()const
{
m_Func(m_o);
};
};
int main() {
return 0;
}
In your code you are tyring to bound a reference to a temporary, namely to copy of argument passed to the constructor. You can try to run the following code snippet to see the difference:
struct Func {
int _i;
void operator()(int i) { cout << i*_i << endl; }
};
class RunFunc
{
Func& m_Func;
int m_o;
public:
RunFunc(Func &func, int o) :m_Func(func), m_o(o)
// RunFunc(Func func, int o) :m_Func(func), m_o(o)
{
};
void operator()()const
{
m_Func(m_o);
};
};
int main() {
Func f{ 5 };
RunFunc rf(f, 2);
rf();
return 0;
}
This is a legacy approach. You can use standard library functor and binder instead. For example:
#include <functional>
#include <iostream>
static void my_callback(int i) {
std::cout<< i << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
std::function<void()> functor;
functor = std::bind(my_callback, 1);
functor();
return 0;
}

How to have a c++ object with a method that takes argument the enclosing class?

I am trying to figure out if there's any known pattern/idiom in c++ for what I am trying to do here. Class A must be composed of an object that has a function whose argument must also be of type A. The following code doesn't compile since typeid may not be used in a constant expression. Any suggestions?
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
struct B {
int f(T& i) { cout << "Hello\n"; }
};
class A {
B<typeid(A)> b;
};
int main()
{
A k;
}
Your stated requirements don't need templates at all, just a forward declaration:
#include <iostream>
class A; // forward declare A
struct B {
int f(A &i); // declaration only, definition needs the complete type of A
};
class A {
B b;
};
int B::f(A &i) { std::cout << "Hello\n"; } // define f()
int main()
{
A k;
}
You are looking for B<A> b; The following program compiles without error or warning on g++ 4.4.3.
#include <iostream>
#include <typeinfo>
using namespace std;
template <typename T>
struct B {
int f(T& i) { cout << "Hello\n"; return 0; }
};
class A {
public:
B<A> b;
};
int main()
{
A k;
return k.b.f(k);
}
Note: If you are using templates only to avoid forward declaration, my solution is wrong. But, I'll leave it here in case you are using templates for some other legitimate reason.

How to call generic template function in a specialization version

Have a problem about how to call the generic template version in a specialization version.
Here is the sample code. But the "vector::push_back(a)" calls itself recursively.
#include <iostream>
#include <vector>
using namespace std;
namespace std
{
template<>
void vector<int>::push_back(const int &a)
{
cout << "in push_back: " << a << endl;
vector::push_back(a); // Want to call generic version
}
}
int main()
{
vector<int> v;
v.push_back(10);
v.push_back(1);
return 0;
}
When you create specialization for some template (no difference class of function), you tell to compiler to generate that one instead of general. So in fact if you have specialization you have no general version for that specialization and you can't call it, because it doesn't exists.
You can simply extract the code into another template function:
template<typename T>
void baseF(T t) { ... }
template<typename T>
void F(T t) { baseF<T>(t); }
template<>
void F<int>(int t) { baseF<int>(t); }
Well, to complement, I think it works for template function specification in some situations.
#include <iostream>
#include <vector>
using namespace std;
class Base
{
public:
virtual int test() {return 0;}
};
class Derived : public Base
{
public:
virtual int test() {return 1;}
};
template<class T>
void TestOutput(T* a)
{
cout << a->test() << endl;
}
template<>
void TestOutput(Derived* a)
{
cout << "something else" << endl;
TestOutput<Base>(a);
}
int main()
{
Derived d;
TestOutput(&d);
}
I compiled it with visual studio 2013 and the output is:
something else
1
Although I don't think you can always find a TestOutput function of Base to call the generic one.