I'm getting a compiler error when I'm trying to initialize my array with function pointers. Without using a class I'm able to run the code fine, but when I incorporate the code in a class I'm getting the error. I suppose this is more of a problem with my understanding of class usage, the scope resolution operator, etc. Any help to get this resolved would be much appreciated.
#include <iostream>
#include <cassert>
using namespace std;
#define F1 0
#define F2 1
#define F3 2
class A
{
private:
bool Func1();
bool Func2();
bool Func3();
public:
bool do_it(int op);
typedef bool (A::*fn)(void);
static fn funcs[3];
protected:
};
A::fn A::funcs[3] = {Func1, Func2, Func3};
int main()
{
A Obj;
cout << "Func1 returns " << Obj.do_it(F1) << endl;
cout << "Func2 returns " << Obj.do_it(F2) << endl;
cout << "Func3 returns " << Obj.do_it(F3) << endl;
return 0;
}
bool A::do_it(int op)
{
assert(op < 3 && op >= 0);
return (this->*(funcs[op]))();
}
bool A::Func1() { return false; }
bool A::Func2() { return true; }
bool A::Func3() { return false; }
The compiler spits out:
15:35:31 **** Build of configuration Debug for project JT ****
make all
make: Warning: File 'objects.mk' has modification time 7.3 s in the future
Building file: ../src/JT.cpp
Invoking: GCC C++ Compiler
g++ -O0 -g3 -Wall -c -fmessage-length=0 -MMD -MP -MF"src/JT.d" -MT"src/JT.o" -o "src/JT.o" "../src/JT.cpp"
../src/JT.cpp:141:41: error: cannot convert ‘A::Func1’ from type ‘bool (A::)()’ to type ‘A::fn {aka bool (A::*)()}’
A::fn A::funcs[3] = {Func1, Func2, Func3};
^
../src/JT.cpp:141:41: error: cannot convert ‘A::Func2’ from type ‘bool (A::)()’ to type ‘A::fn {aka bool (A::*)()}’
../src/JT.cpp:141:41: error: cannot convert ‘A::Func3’ from type ‘bool (A::)()’ to type ‘A::fn {aka bool (A::*)()}’
src/subdir.mk:18: recipe for target 'src/JT.o' failed
make: *** [src/JT.o] Error 1
15:35:32 Build Finished (took 1s.64ms)
Use A::fn A::funcs[3] = {&A::Func1, &A::Func2, &A::Func3};
Related
The book said I cannot change the value of const once I gave it a number, but it seems I can still give it a number even if it was given.
#include<iostream>
using namespace std;
const int fansc(100);
cout<< fansc << endl; //output:100
int fansc(20);
cout<< fansc << endl;//output:20
The C++ code you gave won't compile, and rightly so. A const variable(a) is, well, ... constant. The error is shown in the following program and transcript:
#include <iostream>
using namespace std;
int main() {
const int fansc(100);
cout << fansc << endl;
int fansc(20);
cout << fansc << endl;
}
pax> g++ --std=c++17 -Wall -Wextra -Wpedantic -o prog prog.cpp
prog.cpp: In function ‘int main()’:
prog.cpp:6:9: error: conflicting declaration ‘int fansc’
6 | int fansc(20);
| ^~~~~
prog.cpp:4:15: note: previous declaration as ‘const int fansc’
4 | const int fansc(100);
| ^~~~~
That leaves the Anaconda bit that you mention in a comment. I have little experience with that but it seems to me the only way that would work is if the second fansc definition was somehow created in a different scope to the first. In real C++ code, that would go something like:
#include <iostream>
using namespace std;
int main() {
const int fansc(100);
cout << fansc << endl;
{ // new scope here
int fansc(20);
cout << fansc << endl;
} // and ends here
cout << fansc << endl;
}
And the output of that is:
pax> g++ --std=c++17 -Wall -Wextra -Wpedantic -o prog prog.cpp && ./prog
100
20
100
(a) Yes, I know that's a self-contradiction :-)
I always get a mysterious warning if I compile the following code:
template < void(*FUNC)() >
struct Bla
{
static void Do()
{
if constexpr ( FUNC != nullptr )// << compiler complains here "the address of 'void f1()' will never be NULL [-Waddress]"
{
FUNC();
}
else
{
std::cout << "Nothing" << std::endl;
}
}
};
void f1() { std::cout << "f1" << std::endl; }
int main()
{
Bla<f1>::Do();
Bla<nullptr>::Do();
}
Full warning from g++:
[x#y ~]$ g++ -std=c++20 -g -O2 -Wall -pedantic -Wextra main.cpp
main.cpp: In instantiation of 'static void Bla<FUNC>::Do() [with void (* FUNC)() = f1]':
main.cpp:86:18: required from here
main.cpp:71:13: warning: the address of 'void f1()' will never be NULL [-Waddress]
71 | if constexpr ( FUNC != nullptr )
| ^~
The idea of checking for template parms with constexpr if is not to get a warning if the parameter is a constant :-)
I am wrong or is it simply a gcc bug?
Function foo takes a vector of strings. It's defined as
bool foo(vector<string>& input);
When I call foo with:
foo(vector<string>{"abc"});
my compiler gives the following error:
error: expected '(' for function-style cast or type construction
and points to { as the start of the error. This compiles fine in Xcode but I get the error when running the following via command line with:
g++ -o -std=c++17 main.cpp
What is wrong with my g++ syntax?
G++ Version Information:
g++ --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/include/c++/4.2.1
Apple clang version 11.0.3 (clang-1103.0.32.59)
Target: x86_64-apple-darwin19.4.0
Thread model: posix
Your command line specifies that the output file ("-o") should be called "-std=c++17" – it does not say anything about the language version, so you're compiling as C++03.
Remove the "-o" or add an actual file name.
Also, note that your "g++" is an alias for clang.
I took your code and tried to compile it. For me there was rather problem with trying to pass non const value to function. I changed function argument to const and it compiled and printed without any problem.
#include <iostream>
#include <vector>
bool foo(const std::vector<std::string>& v) {
for (auto& a : v) { std::cout << a << std::endl; }
return true;
}
int main()
{
bool result = foo(std::vector<std::string> {"1", "2", "3" });
// do something with result
return 0;
}
Compiled on: https://www.onlinegdb.com/online_c++_compiler
Function foo expects for an l-value.
You are generating an instance and passing it to the function. But lifetime of the object is not enough for the pass-by-reference call.
Here is an example below; instance of class A is immediately destructed.
#include <iostream>
#include <vector>
#include <string>
using namespace std;
class A {
public:
A(int m): m(m) {
cerr << __func__ << endl;
}
~A() {
cerr << __func__ << endl;
}
int m;
};
int main() {
cerr << __func__ << endl;
A(5);
cerr << __func__ << endl;
return 0;
}
Outputs:
main
A
~A
main
Created shared library with below file
example.cpp
#include <iostream>
template <typename T>
T Max (T & a, T & b)
{
return a < b ? b:a;
}
I was trying to use above library in my code
test.cpp
#include <stdio.h>
#include <iostream>
using namespace std;
template int Max <int> (int & a, int & b);
template double Max <double> (double & a, double & b);
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
return 0;
}
when I compiled above code ,getting the following error
test.cpp:4: error: explicit instantiation of non-template ‘int Max’
test.cpp:4: error: expected ‘;’ before ‘<’ token
test.cpp:5: error: explicit instantiation of non-template ‘double Max’
test.cpp:5: error: expected ‘;’ before ‘<’ token
test.cpp: In function ‘int main()’:
test.cpp:11: error: ‘Max’ was not declared in this scope*
I realize this is a trivial example more for academic purpose than anything else. Otherwise I would recommend scrapping the whole thing and just using std::max from the get-go. The standard library provides a wealth of well-specified and tested functionality for the taking; use it unless you have a damn good reason to reinvent the wheel.
If you seriously want to provide a template declaration of a function in a header, and provide the implementation of said-template in a shared object library, you can do it by using explicit instantiation, which it appears you're attempting. However, your attempt appears to be putting said-same in the wrong module.
One way to do it is as follows:
example.hpp
#ifndef MYLIB_EXAMPLE_HPP
#define MYLIB_EXAMPLE_HPP
// define forward declaration here. no implementation
template<class T> T Max(T lhs, T rhs);
#endif
example.cpp
#include "example.hpp"
// provide implementation here
template<class T>
T Max(T lhs, T rhs)
{
return (lhs < rhs) ? rhs : lhs;
}
// explicit instantiations
template int Max<int>(int,int);
template double Max<double>(double,double);
That's it for the library. An example build using clang would be:
clang++ -std=c++11 -Wall -Wextra -pedantic -fPIC -shared -o libexample.so example.cpp
The resulting shared object library exposes the following symbols:
nm libexample.so
0000000000000f50 T __Z3MaxIdET_S0_S0_
0000000000000f20 T __Z3MaxIiET_S0_S0_
U dyld_stub_binder
so as you can see, they're there in the lib. On to the test program that will consume this library:
test.cpp
#include <iostream>
#include "example.hpp"
int main ()
{
int i = 39;
int j = 20;
std::cout << "Max(i, j): " << Max(i, j) << std::endl;
double f1 = 13.5;
double f2 = 20.7;
std::cout << "Max(f1, f2): " << Max(f1, f2) << std::endl;
return 0;
}
We build it as follows (assuming the library is in the local folder):
clang++ -std=c++11 -Wall -Wextra -pedantic -L. -o test -lexample test.cpp
The resulting program, test, produces the following output:
Max(i, j): 39
Max(f1, f2): 20.7
Honestly, there isn't a ton of value in doing it this way, as any future usages of Max that are not provided in your explicit list will result in linker errors (unless that is the intent, in which case it would do exactly what you're looking for).
My recomendations:
Change example.cpp to header a file, Max is a template function
Remove the forward declarations in the code
Remove #include <stdio.h>, unless that really is used somewhere
example.hpp:
template <typename T>
T Max (T& a, T& b)
{
return a < b ? b : a;
}
test.cpp:
#include <iostream>
using namespace std;
int main ()
{
int i = 39;
int j = 20;
cout << "Max(i, j): " << Max(i, j) << endl;
double f1 = 13.5;
double f2 = 20.7;
cout << "Max(f1, f2): " << Max(f1, f2) << endl;
return 0;
}
I'm unable to figure out what's the problem here. I have a ConsoleIO class, which contains two methods:
static void OutputMessage(const std::string &message);
static void OutputMessageNoNewLine(const std::string &message);
They are defined inline in the header:
inline void ConsoleIO::OutputMessage(const std::string &message)
{
std::cout << message << std::endl;
}
inline void OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
Also another class, ContentParser, with the methods:
static const bool StringEquals(const char *a, const char *b);
template <typename T>
static const std::string NumToString(const T num);
template <typename T>
static const T StringToNum(const std::string &s);
Which are defined in a separate file, ContentParser.cpp.
template <typename T>
const std::string ContentParser::NumToString(const T num)
{
std::ostringstream ss;
ss << num;
return ss.str();
}
I have the following code in the AdventureGame class:
ConsoleIO::OutputMessageNoNewLine(ContentParser::NumToString(num+1));
ConsoleIO::OutputMessage(" - " + decision.choices.at(num).text);
The strange thing is, from the above, the bottom line works fine, but the top produces an error when linking (line 65 error). The StringEquals method also works everywhere.
Here is the build log:
14:03:02 **** Incremental Build of configuration Debug for project AdventureGame ****
Info: Internal Builder is used for build
g++ -O0 -g3 -Wall -c -fmessage-length=0 -std=c++11 -o AdventureGame.o "..\\AdventureGame.cpp"
g++ "-LD:\\Program Files\\tinyxml2-master" -o AdventureGame.exe tinyxml2.o Main.o ContentParser.o AdventureGame.o -ltinyxml
AdventureGame.o: In function `AdventureGame::ProcessDecision()':
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:65: undefined reference to `std::string const ContentParser::NumToString<unsigned int>(unsigned int)'
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:65: undefined reference to `ConsoleIO::OutputMessageNoNewLine(std::string const&)'
D:\adat\eclipse\AdventureGame\Debug/../AdventureGame.cpp:68: undefined reference to `ConsoleIO::OutputMessageNoNewLine(std::string const&)'
collect2.exe: error: ld returned 1 exit status
What am I missing?
This
inline void OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
should be this
inline void ConsoleIO::OutputMessageNoNewLine(const std::string &message)
{
std::cout << message << " ";
std::flush(std::cout);
}
Easy mistake to make.