Code compiles on MSVC, but not on GCC [duplicate] - c++

This question already has an answer here:
how to inherit a class with templates? [duplicate]
(1 answer)
Closed 8 years ago.
I'm new to GCC and am trying to port code to Linux which compiled OK with MSVC.
The code below (a small program wich can be copypasted and compiled) produces the error:
"there are no arguments to ‘num_obj_inc’ that depend on a template parameter,
so a declaration of ‘num_obj_inc’ must be available [-fpermissive]"
#include <iostream>
using namespace std;
#define _SPTRDBG
#ifdef _SPTRDBG
#define SPTRDBG(x) x;
#else
#define SPTRDBG(x)
#endif
template<bool>
struct objCounter
{
void num_obj_inc(){}
void num_obj_dec(){}
};
template<>
struct objCounter<true>
{
#ifdef _SPTRDBG
static int num;
void num_obj_inc() { num++; }
void num_obj_dec() { num--; }
#endif
};
template<class C, bool bCnt=false>
class SPtr
: public objCounter<bCnt>
{
C* p;
public:
SPtr(C *_p)
:p(_p)
{
if ( p ) {
SPTRDBG( num_obj_inc() )
}
}
};
int main()
{
return 0;
}
My guess was that GCC somehow optimize out the noop "num_obj_inc(){}", but this code compiles OK:
struct objCounter
{
void num_obj_inc(){}
void num_obj_dec(){}
};
class SPtr
: public objCounter
{
public:
SPtr(int *p)
//:p(_p)
{
if ( p ) {
SPTRDBG( num_obj_inc() )
}
}
};
What can be cause of the compilation error?

You need to use:
this->num_obj_inc();
See Why do I have to access template base class members through the this pointer? for detailed explanation.

Related

How to pass smart pointer instead of "this" in C++ 11?

I am using c++11 compiler.
I have two classes - class Test and class TestHelper.
The class Test is a friend-to-class TestHelper.
The class Test is only which we can access from outside.
Now, we want to call Test API i.e. setVal(). This setVal() should call
Test2 API i.e. setX and is expecting this pointer. I don't want to use this pointer but want
to use a smart pointer instead. How can I do so?
The notion of this kind of desirability is because of the fact that in reality, my class Test is pretty big. So, I am trying to make a helper class for Test i.e.
class TestHelper;
class Test
{
friend class TestHelper;
int x;
public:
void display() {
std::cout << x;
}
void setVal(int val) {
TestHelper testH;
testH.setX(this, 324);
}
};
class TestHelper
{
public:
void setX(Test *test, int val) {
/** some algorithm here and then change val to something else */
test->x = val*100;
}
};
int main()
{
std::cout << "Hello World!\n";
Test x;
x.setVal(130);
}
I tried changing the prototype from void setX(Test *test, int val)
to void setX(std::shared_ptr<Test> test, int val) but don't know how to pass this pointer
as std::shared_ptr<Test> test here.
So here is working solution with shared pointers. The example doesn't even compile due to missing definitions so you have to restructure your code into headers and cpp files.
Test.h:
#ifndef TEST_H
#define TEST_H
#include <memory>
#include "TestHelper.h"
class Test : public std::enable_shared_from_this<Test>
{
private:
friend class TestHelper;
int x;
public:
void display();
void setVal(int val);
};
#endif
Test.cpp:
#include <iostream>
#include "Test.h"
void Test::display() {
std::cout << x;
}
void Test::setVal(int val) {
TestHelper testH;
testH.setX(shared_from_this(), 324);
}
TestHelper.h:
#ifndef TESTHELPER_H
#define TESTHELPER_H
class Test;
class TestHelper
{
public:
void setX(std::shared_ptr<Test> test, int val);
};
#endif
TestHelper.cpp:
#include <memory>
#include "TestHelper.h"
#include "Test.h"
void TestHelper::setX(std::shared_ptr<Test> test, int val) {
/** some algorithm here and then change val to something else */
test->x = val*100;
}
main.cpp:
#include <iostream>
#include <memory>
#include "Test.h"
int main(void){
std::cout << "Hello World!\n";
auto x = std::make_shared<Test>();
x->setVal(130);
x->display();
}
You can run it here: https://paiza.io/projects/e/79dehCx0RRAG4so-sVZcQw
I don't understand why you want this, here's a few variants that compile
reference
// Reference variant
#include <iostream>
class Test;
class TestHelper
{
public:
void setX(Test & test, int val);
};
class Test
{
friend class TestHelper;
int x;
public:
void display() {
std::cout << x;
}
void setVal(int val) {
TestHelper testH;
testH.setX(*this, 324);
}
};
void TestHelper::setX(Test &test, int val)
{
/** some algorithm here and then change val to something else */
test.x = val*100;
}
int main()
{
Test x;
x.setVal(130);
x.display();
}
http://cpp.sh/7t3ec
shared ptr
// Shared ptr variant
#include <iostream>
#include <memory> // Required for shared_ptrs
class Test;
class TestHelper
{
public:
void setX(std::shared_ptr<Test> test, int val);
};
class Test : public std::enable_shared_from_this<Test>
{
friend class TestHelper;
int x;
public:
void display() {
std::cout << x;
}
void setVal(int val) {
TestHelper testH;
testH.setX(shared_from_this(), 324);
}
};
void TestHelper::setX(std::shared_ptr<Test> test, int val)
{
/** some algorithm here and then change val to something else */
test->x = val*100;
}
int main()
{
auto x = std::make_shared<Test>(); // x needs to be created as shared_ptr or it won't work
x->setVal(130);
x->display();
}
http://cpp.sh/87ao2
Perhaps with these you can refine your question?

Circular dependency in C++ template methods

I've got a problem with a circular dependecy in C++ template methods. I realize there are several similar threads here but they didn't help me with my specific case. This here is a nonsensical example, but it illustrates the issue:
main.cpp
#include "A.h"
int main()
{
float f = 10;
A a;
a.foo( f );
}
A.h
#pragma once
#include "B.h"
#include <iostream>
class A
{
private:
B _b;
public:
A() {}
std::string getName() const { return "A"; }
template<typename T> void foo( T t )
{
if( _b.getActive() )
_b.foo( t, this );
else
std::cout << "A, " << t << std::endl;
}
};
B.h
#pragma once
#include "A.h"
#include <string>
#include <iostream>
class A;
class B
{
private:
bool _active;
public:
B() : _active( false ) {}
bool getActive() const { return _active; }
void setActive( bool active ) { _active = active; }
template<typename T> void foo( T t, const A *a )
{
std::cout << "B, " << a->getName() << std::endl;
}
};
In B.h I can neither forward-declare A (will get error C2039: 'getName': is not a member of 'A'), nor include A.h (will get error C4430: missing type specifier - int assumed.).
Is there a way around this or do I have to completely refactor my code?
EDIT
I'm compiling with MSVC 141 (VS 2017) with /std:c++latest, btw.
The problem here is that getName() in a->getName() is a non-dependent name (it does not depend on the template parameter T), and it is resolved at the point of template definition. But A is incomplete at that point.
As a simple but ugly workaround, we can introduce a fake dependency on T:
template<class T, class S>
struct First {
using Type = T;
};
struct A;
struct B {
template<typename T>
void foo(T t, const typename First<A, T>::Type* a) {
std::cout << "B, " << a->getName() << std::endl;
}
};
A cleaner solution is to move foo() definitions outside classes and include them after both A and B:
// A.h
#pragma once
#include "B.h"
class A {
// ...
template<typename T>
void foo(T t);
};
// A_impl.h
#pragma once
#include "A.h"
template<typename T>
void A::foo(T t) {
// ...
}
// Similar for B.h and B_impl.h
// main.cpp
#include "A_impl.h"
#include "B_impl.h"
int main() {
float f = 10;
A a;
a.foo(f);
}
I'd also like to add a (not so nice) solution, but maybe it's helpful for some:
during investigations it struck me that I had a different project using the same code base which does compile without any issues. I noticed the difference was the new project had the Conformance Mode set to /permissive-, while the old one had not. So if you need a quick solution for MSVC and don't care about standard conformance, you may want to turn this option off. This way, the above code works just as posted.
EDIT
Disclaimer: be aware though that this may break code, as Evg points out in the comment below.

Incomplete type error when using overloaded constructor [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I've added a C++ class to help with simulations I'm running. It was working fine, until I added another constructor with different inititation parameters, after which the compiler complains about an 'incomplete type' error with the original constructor that was working before. CLion also complains it can't find a matching constructor, even though its the same one I've been using until now.
PS. I'm creating 2 separate instances of the class (1 in main, 1 in another class also initialised in main)...not sure if this is maybe an issue?
Here's the code:
SimEnv.hpp
#ifndef SIMENV
#define SIMENV
#include "ClassContainingSomeParams.hpp"
class SimEnv
{
private:
int p1, p2;
public:
SimEnv(ClassContainingParams); // This is the bad constructor
SimEnv(int, int);
};
#endif
SimEnv.cpp
#include "SimEnv.hpp"
/* This is the bad constructor */
SimEnv::SimEnv(ClassContainingSomeParams p) :
p1(p.getP1()), p2(p.getP2())
{}
SimEnv(SimEnv(int p1, int p2) : p1(p1), p2(p2)
{}
ClassContainingSomeParams.hpp
#ifndef CLASSCONTAININGSOMEPARAMS
#define CLASSCONTAININGSOMEPARAMS
#include "SimEnv.hpp"
ClassContainingSomeParams
{
public:
ClassContainingSomeParams();
void runSim();
int getP1();
int getP2();
private:
int p1, p2;
};
#endif
ClassContainingSomeParams.cpp
#include "ClassContainingSomeParams.hpp"
ClassContainingSomeParams::ClassContainingSomeParams() : p1(0), p2(0)
{}
void ClassContainingSomeParams::runSim()
{
SimEnv env(p1, p2);
// Do some stuff
}
main.cpp
#include "ClassContainingSomeParams.hpp"
#include "SimEnv.hpp"
int main()
{
ClassContainingSomeParams p;
SimEnv env(p);
// Do some stuff
return 0;
}
The exact errors I'm getting are
SimEnv.hpp:10:33: error: field 'ClassContainingParams' has incomplete type 'SimEnv'
ClassContainingSomeParams.hpp:5:1: error: 'ClassContainingSomeParams' does not name a type
Do I need to place the class declaration and initialisation into the header file? If so, why?
There is a circular inclusion between ClassContainingParams.hpp and SimEnv.hpp.
change your ClassContainingParams to ClassContainingParams* or const ClassContainingParams& and move the inclusion of ClassContainingParams.hpp in SimEnv.cpp.
#ifndef SIMENV
#define SIMENV
class ClassContainingSomeParams;
namespace Namespace
{
class SimEnv
{
private:
size_t p1, p2;
size_t* pTracker;
void init();
public:
SimEnv(const ClassContainingParams&);
SimEnv(size_t, size_t);
size_t func1();
size_t func2();
};
}
#endif
SimEnv.cpp
#include <SimEnv.hpp>
#include <ClassContainingSomeParams.hpp>
namespace Namespace
{
SimEnv::SimEnv(const ClassContainingSomeParams& p) :
p1(p.getP1()), p2(p.getP2())
{
init();
}
SimEnv(SimEnv(size_t p1, size_t p2) : p1(p1), p2(p2)
{
init();
}
void SimEnv::init()
{
std::cout << "I'm initialised" << '\n';
}
}

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

Using this if it exists / Detecting calling convention of current scope in C++ (thiscall vs cdecl)

I'm trying to write a robust macro that will work within both thiscall and cdecl calling conventions, but to utilize 'this' for additional information if 'this' exists (thiscall).
Is it possible?
Here's an example that does not work:
#define PRINT_IF_THIS_EXISTS \
if (this) printf("this (addr %08x) exists in %s!\n", size_t(this), __FUNCTION__)
struct MyStruct
{
void MyFunc()
{
PRINT_IF_THIS_EXISTS;
}
};
void StaticFunc()
{
PRINT_IF_THIS_EXISTS;
MyStruct ms;
ms.MyFunc();
}
Desired runtime output:
this (addr 0015f330) exists in MyStruct::MyFunc!
Observed compiler error:
Example.cpp(14): error C2355: 'this' : can only be referenced inside non-static member functions
I'm using clang and Visual Studio, and getting it to work in either individually is still useful. This seems similar to SFINAE, but I didn't find anything related to just 'this'
You might come up with something nicer but this just might work.
Tested in MSVC++.
#include <iostream>
#include <stdio.h>
#include <string.h>
#define PRINT_IF_THIS_EXISTS \
if (strchr(__FUNCTION__,':')) printf("this exists in %s!\n", __FUNCTION__)
class test
{
public:
test()
{
PRINT_IF_THIS_EXISTS;
}
};
void staticFunction()
{
PRINT_IF_THIS_EXISTS;
}
int main()
{
PRINT_IF_THIS_EXISTS;
staticFunction();
test t;
std::cin.get();
return 0;
}
is_foo_static in following code checks if X::foo() is a static function.Maybe you can use it in your macro to tell if it is thiscall.
template<typename T>
struct is_foo_static {
template<typename X>
static std::true_type check(X*, decltype(X::foo())* = 0);
static std::false_type check(...);
typedef decltype(check((T*)(0))) _tmp;
static const bool value = _tmp::value;
};
struct FooStatic {
static void foo() {}
};
struct FooNonStatic {
void foo() {}
};
int main(){
cout<<boolalpha
<<is_foo_static<FooStatic>::value<<endl
<<is_foo_static<FooNonStatic>::value<<endl;
return 0;
}