Term not evaluated to a function in C++ - c++

I have following code, which i taken from Boost and simplified for my project. Please accept my aplogies for pasting complete code, i done it so that it will be easy to answer my question. While compiling following code in VS 2008 i am getting followoing error.
error C2064: term does not evaluate to a function taking 3 arguments
I am expecting addOptions retruns OptionsInit object which call function operator with three arguments but that is not happening, can any one please find bug. Thanks in advance.
namespace MyInfrastructure
{
namespace Internal
{
class OptionDescrp;
class OptionsInit;
}
class OptionsCollection
{
public:
OptionsCollection(std::string optCollName);
Internal::OptionsInit addOptions();
private:
// avoid copying and assignment.
// Prohibit copy
OptionsCollection( const OptionsCollection& );
OptionsCollection& operator = (const OptionsCollection& );
void add(Internal::OptionDescrp* desc) {m_options.push_back(desc);}
std::vector<Internal::OptionDescrp* > m_options;
std::string m_optCollName;
friend class Internal::OptionsInit;
};
}
////////////
#include <string>
#include <vector>
#include <assert.h>
#include "PrgmOptions.h"
namespace MyInfrastructure
{
namespace Internal
{
class OptionDescrp
{
public:
OptionDescrp(std::string pcOptname, std::string description, bool isOptValueReq);
virtual ~OptionDescrp(){ };
private:
std::string m_shortName; // option short name.
std::string m_longName; // option long name.
std::string m_description;// option description.
};
class OptionsInit
{
public:
OptionsInit(OptionsCollection* coll){ owner = coll; }
OptionsInit& operator()(std::string name, std::string description, bool isOptValReq);
private:
OptionsCollection* owner;
};
}
/////
namespace MyInfrastructure
{
OptionsCollection::OptionsCollection(std::string optCollName) : m_optCollName(optCollName) {}
Internal::OptionsInit OptionsCollection::addOptions()
{
return Internal::OptionsInit(this);
}
}
namespace MyInfrastructure
{
namespace Internal
{
// Class Options description definitions.
OptionDescrp::OptionDescrp(std::string pcOptname, std::string description, bool isOptValueReq)
: m_description(description)
{
std::string name(pcOptname);
std::string::size_type n = name.find(',');
if (n != std::string::npos)
{
assert(n == name.size()-2);
m_longName = name.substr(0, n);
m_shortName = '-' + name.substr(n+1,1);
}
else
{
m_longName = name;
}
}
// Class Options Init definitions.
OptionsInit& OptionsInit::operator()(std::string name, std::string description, bool isOptValReq)
{
OptionDescrp* opt = new OptionDescrp(name, description, isOptValReq);
owner->add(opt);
return *this;
}
}
}
//////
int main(void)
{
MyInfrastructure::OptionsCollection desc("myoptions");
**desc.addOptions()("help", "produce help message", false); // error is thrown here**
return 0;
}

The example code in the question compiles without errors with Visual 2008, gcc, Visual 2003 when we copy all in a single file.
You have error C2064, it is probably because you either have a #define or another definition somewhere in other headers that you did not include in your sample, or that somehow you are not compiling exactly the sample code.
Try to copy all the sample code in a single file and compile that.

Interesting code: OptionsInit returned by addOptions() is a temporary. You are then calling a non-const method on it, which is allowed, but it returns a non-const reference to itself which is also allowed because it's a non-const method. But that means essentially you "backdoor" binding a non-const reference to a temporary...
I assume the two asterisks before desc.addOptions are not really in your code as there is no operator* overloaded here.
Perhaps if you make operator() const and return const-reference it will work.

problem is with VS2008. I compiled with VS2010, it compiled fine. Thanks all for the inputs.

Related

Seperating C++ Nested Classes into their Own Header Files

new to this site and also C++ but hoping to see some guidance from everyone.
I had a pretty fun project idea to learn C++ digging deeper with APIs, classes, references, etc. and currently I have a working example of code where everything exist within the main.cpp file. The issue I am facing is that when i move the classes (inner and outer) to their own respective header files the code no longer compiles.
The reason for the nested classes is that the OuterAPI serves as the main entry point to the API and has many lower level APIs that can be then accessed beneath it (people, licenes, roles, etc). This way users of API would only have to create an object for the OuterAPI and then dot notation for underlying resource and method.
Here is the working example in the main.cpp
#include <iostream>
#include <nlohmann/json.hpp>
#include <cpr/cpr.h>
using json = nlohmann::json;
class OuterAPI {
private:
class InnerAPI {
private:
OuterAPI& api;
public:
InnerAPI(OuterAPI& a) :api(a) {}
json get() {
cpr::Response r = cpr::Get(
cpr::Url{ api.baseUrl + "resource" },
cpr::Bearer{ api.token }
);
return json::parse(r.text)
};
std::string token;
std::string baseUrl = "";
public:
InnerAPI people;
OuterAPI(std::string t) : token(t), people(*this) {}
};
int main(int argc, char** argv)
{
std::string token = "";
OuterAPI api(token);
json jsonData = api.people.get();
std::cout << jsonData.dump(4) << std::endl;
return 0;
}
Here is me moving everything to respective header/cpp files
OuterAPI.h
#pragma once
class OuterAPI {
private:
class InnerAPI;
std::string token;
std::string baseUrl = "";
public:
OuterAPI(std::string t);
~OuterAPI();
InnerAPI* people;
};
OuterAPI.cpp
#include "WebexAPI.h"
#include "PeopleAPI.h"
OuterAPI::OuterAPI(std::string t) : token(t) {
people = new InnerAPI(*this);
}
OuterAPI::~OuterAPI() { delete people; }
InnerAPI.h
#pragma once
#include <nlohmann/json.hpp>
#include <cpr/cpr.h>
#include "OuterAPI.h"
using json = nlohmann::json;
class OuterAPI::InnerAPI {
private:
OuterAPI& api;
public:
InnerAPI(OuterAPI& a);
json get();
};
InnerAPI.cpp
#include "InnerAPI.h"
OuterAPI::InnerAPI::InnerAPI(OuterAPI& a) : api(a) {}
json OuterAPI::InnerAPI::get() {
cpr::Response r = cpr::Get(
cpr::Url{ api.baseUrl + "resource" },
cpr::Bearer{ api.token }
);
return json::parse(r.text);
main.cpp (finally) - this is where the compiler error occurs at api.people.get() "expression must have class type but has type "OuterAPI::InnerAPI *"
int main(int argc, char** argv)
{
std::string token = "";
OuterAPI api(token);
json jsonData = api.people.get(); // COMPILER ERROR "expression must have class type but has type "OuterAPI::InnerAPI *"
std::cout << jsonData.dump(4) << std::endl;
return 0;
}
From this I believe the issue is associated with me having to define the InnerAPI object people as a pointer inside of OuterAPI but from here I cant seem to come to a resolution.
Also, feel free to critique my design as well, like I say I am new to C++ so want to make sure I can do a good job. Thanks.
In OuterAPI* you have declared people as a member of type InnerAPI*.
You can either call your API using api.people->get() or make the member a InnerAPI instead.
EDIT:
It seems the error, besides the pointer thing, comes from how you handle file includes. I managed to get a working version on REPL.it. I made slight adjustments so I wouldn't have to bring both libraries in so focus on the gist of it. Here it is:
OuterAPI.h
#pragma once
#include <string>
class OuterAPI {
private:
class InnerAPI;
std::string token;
std::string baseUrl = "";
public:
OuterAPI(std::string t);
~OuterAPI();
InnerAPI* people;
};
InnerAPI.j
#pragma once
#include "./OuterAPI.h"
class OuterAPI::InnerAPI {
private:
OuterAPI& api;
public:
InnerAPI(OuterAPI& a);
std::string get();
};
OuterAPI.cpp
#include "./OuterAPI.h"
#include "./InnerAPI.h"
OuterAPI::OuterAPI(std::string t) : token(t) {
people = new InnerAPI(*this);
}
OuterAPI::~OuterAPI() { delete people; }
InnerAPI.cpp
#include "./OuterAPI.h"
#include "./InnerAPI.h"
OuterAPI::InnerAPI::InnerAPI(OuterAPI& a) : api(a) {}
std::string OuterAPI::InnerAPI::get() {
return api.baseUrl + "resource";
}
Make sure you include everything you intend to use in every file where you intend to do so.
Separating declaration and definition is pretty common.
It's a way to reduce compile time on large projects.
Thankfully modules will soon™ make linking a thing of the past.
To address the error message: you declare people as a raw member pointer of the class OuterAPI… You cannot access a member through a pointer using operator ., you need to use operator ->.

Why is my class constructor being called twice?

I've got a base class Container with a derived class Player_Inventory. There can only be one Player_Inventory so my code throws an exception if for some reason a second one is created.
The problem I'm having is that my code is failing my test as it throws the exception even on what is supposed to be the very first construction of the Player_Inventory class. I've debugged the code and two things are happening which I don't quite understand - the number attribute is not tracked by the debugger (at least not in the GUI on VSC), and it seems that right after hitting the first REQUIRE statement, the constructor is called again, thus triggering the exception.
Can anyone help?
After rewriting my constructor method, I'm still getting a similar error.
My revised code is as follows:
containers.h
#include<iostream>
#include<string>
#include<vector>
class Item { // Placeholder class for items
public:
std::string name;
Item(std::string n) : name{n} {};
};
class Container {
protected:
std::string name;
std::string description;
std::vector<Item> contents;
public:
Container(std::string, std::string);
std::string get_name() {return name;}
std::string get_description() {return description;}
std::vector<Item> get_contents() {return contents;}
};
containers.cpp (there are more methods defined in this file which aren't used here)
#include<iostream>
#include<string>
#include "containers.h"
Container::Container(std::string n, std::string desc) : name{n}, description{desc} {};
player_inventory.h
#include "containers.h"
class Player_Inventory : public Container {
public:
static int number;
Player_Inventory(std::string, std::string);
};
player_inventory.cpp
#include<iostream>
#include<stdexcept>
#include "player_inventory.h"
Player_Inventory::Player_Inventory(std::string n, std::string desc): Container(n, desc) {
number += 1;
if (number > 1){
throw std::invalid_argument("You can only have one inventory!");
}
};
int Player_Inventory::number = 0;
test_file.cpp
#include "../lib/Catch2/catch.hpp"
#include "player_inventory.h"
#include<iostream>
#include<string>
#include<vector>
SCENARIO("A player can have an inventory.") {
WHEN("A player inventory is created.") {
Player_Inventory myInventory("My Inventory", "Inventory for the player");
THEN("The created inventory has the correct attribute values.") {
REQUIRE(myInventory.get_name() == "My Inventory");
REQUIRE(myInventory.get_description() == "Inventory for the player");
REQUIRE(myInventory.get_contents().empty());
} // The code works fine when only up to here is included
AND_THEN("Only one player inventory can exist.") { // as soon as this line is included it tries to create another player_inventory object, causing the fail
REQUIRE_THROWS((Player_Inventory myOtherInventory("Second Inventory", "Testing for another one"))); // These two lines were not included but I've included them here as this is the test I wanted to run
REQUIRE(myInventory.get_number() == 1);
}
}
}
Not sure if related, but that's how you should call the Base constructor:
Player_Inventory(std::string n, std::string desc) : Container(n, desc) {
}

Compiler does't recognize overloaded method in another method

I have two classes: "Station" which has method getName() returning string and "Profit" which has the overloaded method sellAt(string stName), sellAt(Station st). To avoid duplicate code I call sellAt(string stName) in sellAt(string stName), however in some cases (see code example below) compiler gives an error: "no instance of overloaded function "Profit::SellAt" matches the argument list. Argument types are: (std::string)". Is it a bug or I miss something?
Station.h
#pragma once
#include <string>
using namespace std;
class Station
{
private:
string sName;
public:
Station(string name);
string getName();
};
Station.cpp
#include "Station.h"
Station::Station(string name)
:sName(name)
{}
string Station::getName()
{
return sName;
}
Profit.h
#pragma once
#include "Station.h"
#include <string>
class Profit
{
public:
double SellAt(string& stName);
double SellAt(Station& st);
};
Profit.cpp
#include "Profit.h"
double Profit::SellAt(const string& stName)
{
// do stuff
}
// Works as expected
double Profit::SellAt(Station& st)
{
string stName = st.getName();
return SellAt(stName);
}
// Compile error
double Profit::SellAt(Station& st)
{
return SellAt(st.getName());
}
// Compile error
double Profit::SellAt(Station& st)
{
double result = SellAt(st.getName());
return result;
}
Yksisarvinen answered in the comment below the original question:
st.getName() is a temporary. You cannot bind non-const reference to a temporary. I suppose you shouldn't want to modify stName in Profit::SellAt(), so change the type of argument to const std::string&.
Thanks for the help!

Enum in a class with strings

I'm trying to implement a class (C++) with an enum (with the permitted parameters). I got a working solution, but if I try to extend the functionality I get stuck.
Header data_location.hpp
class DataLocation
{
private:
public:
enum Params { model, period };
std::string getParamString(Params p);
};
Program data_location.cpp
string DataLocation::getParamString(Params p){
static const char * ParamsStrings[] = {"MODEL", "PERIOD"};
return ParamsStrings[p];
}
The array ParamsStrings should be generally available in the class, because I need a second method (with inverse function) returning the enum value given a string.
If I try to define the array in the header I get the error:
in-class initialization of static data member ‘const char* DataLocation::ParamsStrings []’ of incomplete type
Why is the type incomplete? The compiler is for sure able to counts the strings in the array, isn't it?
In case there is no way to get my code working, is there an other way? With 1) no XML; 2) no double definition of the strings; 3) not outside the class; 4) no in code programmed mapping.
In class (header) use keyword static and initialize it outside (.cpp) without the static keyword:
class DataLocation {
public:
enum Params { model, period };
string getParamString(Params p);
static const char* ParamsStrings[];
// ^^^^^^
};
const char* DataLocation::ParamsStrings[] = {"MODEL", "BLLBLA"};
//^^^^^^^^^^^^^^^^^^^^^^^^
The code you have posted is perfectly fine.
Here's the proof:
#include <iostream>
#include <string>
struct DataLocation
{
enum Params { model, period };
std::string getParamString(Params p){
static const char * ParamsStrings[] = {"MODEL", "PERIOD"};
return ParamsStrings[p];
}
};
int main()
{
auto a = DataLocation();
std::cout << a.getParamString(DataLocation::model) << std::endl;
return 0;
}
The error message you are getting is not to do with definition of a static data member in an inline function - that's allowed.
There's something else you're not showing us.
The main issue in my question (the second part) was that if I split the class in .hpp and .cpp the definition of the array (I mixed *char and string) has also to be split:
// data_location.hpp
class DataLocation {
static const char * ParamsStrings[];
}
// data_location.cpp
const char * ParamsStrings[] = {"MODEL", "PERIOD"};
At the end I introduced a consistency check to be sure that the number of values in enum growths as the number of strings. Because the array in C++ is somehow limited I had to go for a std::vector (to get the size).
Code for data_location.hpp
#ifndef DATA_LOCATION_HPP_
#define DATA_LOCATION_HPP_
#include <string>
#include "utils/dictionary.hpp"
extern const char* ENV_DATA_ROOT;
struct EDataLocationInconsistency : std::runtime_error
{
using std::runtime_error::runtime_error;
};
struct EDataLocationNotValidParam : std::runtime_error
{
using std::runtime_error::runtime_error;
};
class DataLocation
{
private:
std::string mRootLocation;
static const std::vector<std::string> msParamsStrings;
static bool msConsistenceCheckDone;
public:
DataLocation();
std::string getRootLocation();
std::string getLocation(Dictionary params);
enum Params { model, period, LAST_PARAM};
std::string Param2String(Params p);
Params String2Param(std::string p);
};
#endif
Code for data_location.cpp
#include "data_location.hpp"
#include <string>
#include <cstdlib>
using namespace std;
const char* ENV_DATA_ROOT = "DATA_ROOT";
bool DataLocation::msConsistenceCheckDone = false;
DataLocation::DataLocation() {
mRootLocation = std::getenv(ENV_DATA_ROOT);
if (not msConsistenceCheckDone) {
msConsistenceCheckDone = true;
if (LAST_PARAM+1 != msParamsStrings.size()) {
throw(EDataLocationInconsistency("DataLocation: Check Params and msParamsStrings"));
}
}
}
string DataLocation::getRootLocation() {
return mRootLocation;
}
string DataLocation::getLocation(Dictionary params) {
// to do
return "";
}
const vector<string> DataLocation::msParamsStrings = { "MODEL", "PERIOD", ""};
string DataLocation::Param2String(Params p) {
if (p>=msParamsStrings.size()) {
throw(EDataLocationNotValidParam("Parameter not found"));
}
return msParamsStrings[p];
}
DataLocation::Params DataLocation::String2Param(string p) {
for (int i = 0; i < msParamsStrings.size(); i++) {
if (p == msParamsStrings[i])
return (Params)i;
}
throw(EDataLocationNotValidParam("Parameter not found"));
}
And also a unit test:
#include <boost/test/unit_test.hpp>
#include "data_location.hpp"
#include <string>
using namespace std;
BOOST_AUTO_TEST_SUITE( data_location )
BOOST_AUTO_TEST_CASE(data_location_1) {
DataLocation dl;
auto s = dl.getRootLocation();
BOOST_CHECK_EQUAL(s, "/home/tc/data/forex" );
BOOST_CHECK_EQUAL(dl.Param2String(DataLocation::period),"PERIOD");
BOOST_CHECK_EQUAL(dl.String2Param("PERIOD"),DataLocation::period);
BOOST_CHECK_THROW(dl.String2Param("SOMETHING"), EDataLocationNotValidParam);
BOOST_CHECK_THROW(dl.Param2String((DataLocation::Params)100), EDataLocationNotValidParam);
}
BOOST_AUTO_TEST_SUITE_END()
C++ is very picky about what it will let you initialize inside of a class definition; there are some particularly non-intuitive rules surrounding static members. It all has to do with the ODR, and why all the rules are the way they are is not especially important.
To cut to the chase, making your array a static constexpr const member should shut the compiler up. With the C++11 standard, the restrictions were relaxed a bit, and one of the new stipulations was that static constexpr members can be initialized inline. This is perfect for your application, since the strings in your array are compile-time constants.
The recent g++ compiler which support C++0x or later compiles thus code. Pure C compile compiles, too. Because strings in initialization like {"MODEL", "PERIOD"}; implemented as const char * pointer to the char array.

How to include a declaration in the comma operator?

I have two simple testing lines:
cout<<(cout<<"ok"<<endl, 8)<<endl;
cout<<(int i(8), 8)<<endl;
The first line worked, but the second failed compilation with
error: expected primary-expression before 'int'
For some reason, I do need a declaration in the comma operator. To be more specific, I want to declare some variables, obtain their values, and assign them to my constant class members from the initialization list of my class constructor. Following shows my intentions. If not achievable using comma operator, any another suggestions?
#include <iostream>
#include <fstream>
#include <string>
#include <sstream>
#include <cstdlib>
using namespace std;
void readFile(const string & fileName, int & a, int & b)
{
fstream fin(fileName.c_str());
if (!fin.good()) {cerr<<"file not found!"<<endl; exit(1);}
string line;
getline(fin, line);
stringstream ss(line);
try {ss>>a>>b;}
catch (...) {cerr<<"the first two entries in file "<<fileName<<" have to be numbers!"<<endl; exit(1);}
fin.close();
}
class A
{
private:
const int _a;
const int _b;
public:
A(const string & fileName)
:
_a((int a, int b, readFile(fileName,a,b), a)),
_b((int a, int b, readFile(fileName,a,b), b))
{
/*
int a, b;
readFile(fileName,a,b);
_a = a;_b = b;
*/
}
void show(){cout<<_a<<" "<<_b<<endl;}
};
int main()
{
A a("a.txt");
a.show();
}
Declarations are statements and not expressions. You cannot place statements inside of expressions, though you can place expressions inside of statements. Accordingly, you cannot declare a variable in the way that you're describing above. You'll need to separate it out into multiple different statements.
I would be surprised if if you actually needed to do this. If you do, there is probably something problematic about your design.
Hope this helps!
You should have a look at Boost Phoenix (which has phoenix::let to do roughly this). Bear in mind, Phoenix is an eDSL, really (embedded domain specific language).
You could do an ugly trick and abuse lambdas:
cout<< ([]->int{ int i(8); return 8; })() <<endl;
A lambda allows a declaration within an expression. So this is possible:
std::cout << ([]{ int i(8); m_i = i; }(), 8) << std::endl;
But it's really weird - I assume this will be in some #define macro that makes it appear closer to normal.
You cannot. This is unpossible in C++. The fact that you are trying to do this is also a code smell. Something's not right here.
I want to declare some variables, obtain their values, and assign them
to my constant class members from the initialization list of my class
constructor. Not sure how to achieve this.
You didn't say what you intended to do with these variables you declare after you've used the values, but I'm guessing that once you've finished with the values, you've finished with the variables. In other words, they are temporary.
Your edited example suggests that my assumption is correct. It also confirms the code smell. Based on your (intended) code, you are going to read the file twice.
I'd say the most straightforward way to do this is to use an intermediary, kind of like a factory class. This also has the benefit of being able to read the file only once, as opposed to twice as you are doing now.
void readFile (const std::string& fileName, int& a, int& b)
{
// some magic
a = 42;
b = 314;
}
class FileReader
{
public:
FileReader (const std::string fileName)
:
mFileName (fileName),
mA (42),
mB (314)
{
// something happens like reading the file
}
int GetA () const
{
return mA;
}
int GetB () const
{
return mB;
}
private:
int mA;
int mB;
std::string mFileName;
};
class A
{
private:
const int mA;
const int mB;
public:
A (const FileReader& reader)
:
mA (reader.GetA()),
mB (reader.GetB())
{
}
};
Using this FileReader is simple:
int main()
{
A myA (FileReader ("somefile.txt"));
}