Default container arguments - c++

The following header works with the commented part as expected when I call the function bat with no arguments:
class Test
{
public:
void bat(std::vector<int> k = std::vector<int>()) {}
//void cat(std::map<int, std::vector<int> > k = std::map<int, std::vector<int> >()) {}
};
But when I try using the cat function in the header:
class Test
{
public:
void bat(std::vector<int> k = std::vector<int>()) {}
void cat(std::map<int, std::vector<int> > k = std::map<int, std::vector<int> >()) {}
};
I get:
test.h:14: error: expected ',' or '...' before '>' token
test.h:14: error: wrong number of template arguments (1, should be 4)
/usr/lib/gcc/x86_64-redhat-linux/4.1.2/../../../../include/c++/4.1.2/bits/stl_map.h:92: error: provided for 'template<class _Key, class _Tp, class _Compare,\
class _Alloc> class std::map'
test.h:14: error: default argument missing for parameter 2 of 'void Test::cat(std::map<int, std::vector<int, std::allocator<int> >, std::less<int>, std::all\
ocator<std::pair<const int, std::vector<int, std::allocator<int> > > > >, std::vector<int, std::allocator<int> >)'
How come? And are there easy workarounds for this? hopefully not requiring a pointer type change in the interface?
This is my full header:
#ifndef TEST_H
#define TEST_H
#include <map>
#include <vector>
#include <sstream>
#include <iostream>
class Test
{
public:
//void bat(std::vector<int> k = std::vector<int>()) {}
void cat(std::map<int, std::vector<int> > k = std::map<int, std::vector<int> >()) {}
};
#endif
so all the right includes are there. My version of GCC is terribly outdated (well not at home, ill try it at home too) - but at work it's 4.1.2

The code looks OK, but fails on gcc 4.3.4, see here, but compiles fine with 4.6 onwards (I haven't tested 4.4 or 4.5). So it looks like the workaround is to use a newer gcc.
#include <map>
#include <vector>
class Test
{
public:
void bat(std::vector<int> k = std::vector<int>()) {}
void cat(std::map<int, std::vector<int> > k = std::map<int, std::vector<int> >
()) {}
};
int main() {
}
Concerning default parameters, it may be an idea to drop them altogether:
class Test {
public:
void bat(std::vector<int> k) {}
void bat() {}
void cat(std::map<int, std::vector<int> > k) {}
void cat() {}
};
otherwise, you couple the default parameters to the interface, meaning you cannot change them without requiring re-compilation of all client code.

The code you've posted seems fine, so I'm going to turn on my Psychic Debugger module.
Did you:
#include <vector>
...in your header?

From the other posts here, it looks like it could be a compiler problem, in which case, you can get around it by using a typedef instead of the map type directly.
#include <vector>
#include <map>
class Test
{
public:
typedef std::map<int, std::vector<int> > MyMap;
void bat(std::vector<int> k = std::vector<int>()) {}
void cat(MyMap k = MyMap()) {}
};
int main()
{
}

This is C++ core Defect Report 325 http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#325
GCC 4.4 implements the suggested (but not yet official) resolution of the DR, see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=57#c36

Related

What's the right way to make a pair with unique_ptr?

I am trying to make_pair with a unique_ptr like in the example below
(The code is a C++ implementation of the Facade Design pattern)
#include <unordered_map>
#include <utility>
#include <functional>
using namespace std;
// Step 1 : Design the Interface
class IAccount {
protected:
int accountNo;
int cash;
public:
virtual void deposit(float amount);
virtual void withdraw(float amount);
virtual void transfer(float amount);
virtual int getAccountNumber() = 0;
};
// Step 2 : Implement the interface with one or more subtypes
class Current : public IAccount{
public:
Current(int amt) { cash = amt; }
int getAccountNumber() {
return accountNo;
}
};
class Savings : public IAccount{
public:
Savings(int amt) { cash = amt; }
int getAccountNumber() {
return accountNo;
}
};
// Step 3: Create the Facade class and wrap the classes that implement the Interface
class BankService {
unordered_map<int, unique_ptr<IAccount>> *bankAccounts;
int index;
public:
BankService(): index(0){
bankAccounts = new unordered_map<int, unique_ptr<IAccount>>();
}
int createNewAccount(string name, int amount, string type, int accountNo) {
unique_ptr<IAccount> newAccount;
if(type.compare("current")) {
newAccount.reset(new Current(amount));
}
// Add to the unordered list --- Error here ---
pair<int, unique_ptr<IAccount>> toBeInserted = make_pair(accountNo, newAccount);
bankAccounts->insert(toBeInserted);
return accountNo;
}
};
The code spits out this error :
/Library/Developer/CommandLineTools/usr/include/c++/v1/vector:266:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/__bit_reference:15:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/algorithm:639:
/Library/Developer/CommandLineTools/usr/include/c++/v1/utility:634:12: error: no matching constructor for initialization of 'pair<typename
__make_pair_return<int &>::type, typename __make_pair_return<unique_ptr<IAccount, default_delete<IAccount> > &>::type>' (aka 'pair<int,
std::__1::unique_ptr<IAccount, std::__1::default_delete<IAccount> > >')
return pair<typename __make_pair_return<_T1>::type, typename __make_pair_return<_T2>::type>
^
If I change it to :
// Add to the unordered list (note added const)
pair<const int, unique_ptr<IAccount>> toBeInserted = make_pair(accountNo, newAccount);
bankAccounts->insert(toBeInserted);
I am greeted by :
In file included from ./DesignPatterns/Structural/./../../Include/Common.h:1:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/vector:266:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/__bit_reference:15:
In file included from /Library/Developer/CommandLineTools/usr/include/c++/v1/algorithm:640:
/Library/Developer/CommandLineTools/usr/include/c++/v1/memory:1783:31: error: call to implicitly-deleted copy constructor of 'std::__1::pair<const
int, std::__1::unique_ptr<IAccount, std::__1::default_delete<IAccount> > >'
::new((void*)__p) _Up(_VSTD::forward<_Args>(__args)...);
I tried compiling with with both Clang++ and G++
Clang version: clang-900.0.39.2
G++ version : 4.2.1
Platform: OS x - x86_64-apple-darwin16.6.0
Is this due to the old version of G++ shipped by Apple?
Is this due to the old version of G++ shipped by Apple?
No. It is because you are trying to copy the unique pointer by passing it to make_pair and insert.
std::unique_ptr is not copyable. In fact it is move-only. Change to:
pair<int, unique_ptr<IAccount>> toBeInserted = make_pair(accountNo, std::move(newAccount));
bankAccounts->insert(std::move(toBeInserted));

Returning a map of structs from within a class (where the struct definition is within the class): compile error

I have a class, and within that class I define a struct. The struct has overloaded comparison operators so that it can be used with a map (with an int as the key).
Prior to messing with classes, I had the struct defined in a .cc file, and that file also contained a function which returned a map of this struct. It worked.
Now I want to have the struct defined in the class header, and the class should have a function which returns a map of structs.
Here is a simplified version of my code, which compiles with the same error as the full version. I don't understand the error, and would appreciate any help!
Cheers.
myclass.h:
#include <map>
class myclass {
public:
struct mystruct {
int i;
mystruct();
mystruct(int j);
bool operator==(const mystruct& rhs);
bool operator>(const mystruct& rhs);
bool operator<(const mystruct& rhs);
};
::std::map<int,mystruct> getStructMap();
};
myclass.cc:
#include <map>
#include "myclass.h"
myclass::mystruct::mystruct(int j) : i(j) {};
myclass::mystruct::mystruct() : i(-1) {};
bool ::myclass::mystruct::operator==(const ::myclass::mystruct& rhs) {return i==rhs.i; }
bool ::myclass::mystruct::operator>(const ::myclass::mystruct& rhs) {return i>rhs.i; }
bool ::myclass::mystruct::operator<(const ::myclass::mystruct& rhs) {return i<rhs.i; }
::std::map<int,::myclass::mystruct> ::myclass::getStructMap() {
::std::map<int,::myclass::mystruct> structMap;
for (int i=0;i<5;i++) structMap[i]=::myclass::mystruct(i);
return structMap;
}
myprogram.cc:
#include <iostream>
#include <map>
#include "myclass.h"
int main() {
myclass myobj;
::std::map<int,::myclass::mystruct> mymap;
mymap=myobj.getStructMap();
}
compile error:
> g++ -o myprogram myprogram.cc myclass.cc
myclass.cc:12: error: ‘class std::map<int, myclass::mystruct, std::less<int>,std::allocator<std::pair<const int, myclass::mystruct> > >::myclass’ has not been declared
myclass.cc:12: error: ISO C++ forbids declaration of ‘getStructMap’ with no type
myclass.cc: In function ‘int getStructMap()’:
myclass.cc:15: error: cannot convert ‘std::map<int, myclass::mystruct, std::less<int>, std::allocator<std::pair<const int, myclass::mystruct> > >’ to ‘int’ in return
Currently your code in parsed as
/*missing type*/ ::std::map<int,::myclass::mystruct>::myclass::getStructMap()
Thus, first error, map doesn't have myclass member (or subclasses, method, typedef, ...)
then the second error : no return type (so assuming int and thus the conversion error).
So to solve that, in myclass.cc, you may remove extra :: as follow:
::std::map<int,::myclass::mystruct> myclass::getStructMap() {
or add extra parenthesis:
::std::map<int,::myclass::mystruct> (::myclass::getStructMap()) {

Sorting std::map based on the data (map->vector->sort)

I want to sort a std::map based on the data (second field). However the second field itself is a structure and I want to sort based on one of its elements. Based on what is suggested here and its reference, decided to copy the map to a vector and then use std::sort. Here is the class implementtion
#include <iostream>
#include <vector>
#include <map>
#include <utility>
class foo() {
foo() {}
void bar()
{
aDeltaMap theDeltaMap;
// insert some elements to theDeltaMap
aDeltaVector theDeltaVec( theDeltaMap.begin(), theDeltaMap.end() );
std::sort(theDeltaVec.begin(), theDeltaVec.end(), descend_rep<deltaPair>() ); //ERROR
}
private:
typedef struct entry {
entry( int r, int mc ) : rep(r), missCounter(mc) {}
int rep;
int missCounter;
} aDeltaEntry;
typedef std::map< int, aDeltaEntry > aDeltaMap;
typedef std::pair< int, aDeltaEntry > deltaPair;
typedef std::vector< deltaPair > aDeltaVector;
struct descend_rep
: std::binary_function<deltaPair,deltaPair,bool>
{
inline bool operator()(const deltaPair& lhs, const deltaPair& rhs) { return lhs.second.rep > rhs.second.rep; };
};
};
At the line of sort function, I get this error
error C2275: illegal use of this type as an expression
error C2059: syntax error : ')'
What did I missed?
One error is that descent_rep is not a class template, so you need to replace
descend_rep<deltaPair>()
by
descend_rep()
You should make descend_rep's bool operator() const too, since comparing its operands does not change its state.

Invalid template arguments on map std::map< std::string, Stock*> &stocks

I have the declaration (or similar)
std::map< std::string, Stock*> &stocks;
throughout my code. Eclipse does not like this and produces a "Invalid template arguments" error.
Stock is declared as:
class Stock {
public:
Stock(std::string, qbbo::Financial_status_indicator, qbbo::Security_class,
qbbo::Current_trading_state,
qbbo::Market_category, qbbo::Reg_sho_action);
~Stock();
void setFinancialStatusIndicator(qbbo::Financial_status_indicator financialStatusIndicator);
void setSecurityClass(qbbo::Security_class securityClass);
void setCurrentTradingState(qbbo::Current_trading_state tradingState);
void setMarketCategory(qbbo::Market_category marketCategory);
void setREGShoAction(qbbo::Reg_sho_action regSHOAction);
bool isStockTrading();
private:
enum StockState {
STOCK_STATE_OK, STOCK_STATE_UNKNOWN, STOCK_STATE_UNEXPECTED_CHARACTERISTIC
};
std::string name;
int inventory;
StockState currentState;
// Expected values initialised in constructor
qbbo::Financial_status_indicator expectedFinancialStatusIndicator;
qbbo::Security_class expectedSecurityClass;
qbbo::Current_trading_state expectedCurrentTradingState;
qbbo::Market_category expectedMarketCategory;
qbbo::Reg_sho_action expectedRegSHOAction;
// Actual values as set by messages
qbbo::Financial_status_indicator financialStatusIndicator;
qbbo::Security_class securityClass;
qbbo::Current_trading_state currentTradingState;
qbbo::Market_category marketCategory;
qbbo::Reg_sho_action regSHOAction;
void nextState();
};
I cannot see whats invalid about this declaration and it compiles fine. Is there something I'm missing and Eclipse is catching?
Short Self Contained Correct Example
#include <string>
#include <map>
#include "stock.h"
int main() {
std::map<std::string, Stock*> stocks;
}
Turned out to be an eclipse error. Creating a new project and re-following the steps Eclipse CDT C++11/C++0x support sorted it.

Do Boost MultiIndex Containers work with inherited class members?

I would like to use boost's multi-index container with a class hierarchy. Is this possible?
If I try:
#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
using namespace ::boost;
using namespace ::boost::multi_index;
class A{
public:
int m;
A(int p = 0){m = p;};
};
class B: public A{
public:
int n;
B(int p = 0, int q = 0): A(p){ n = q;};
};
typedef multi_index_container<
B,
indexed_by<
ordered_unique<identity<B> >,
ordered_non_unique<member<B, int, &B::m> >
>
> mindex;
int main(void){
return 0;
}
I get the following errors:
multiindextest.cpp:25: error: could not convert template argument ‘&A::m’ to ‘int B::*’
multiindextest.cpp:25: error: template argument 1 is invalid
multiindextest.cpp:26: error: template argument 2 is invalid
multiindextest.cpp:27: error: template argument 2 is invalid
multiindextest.cpp:27: error: invalid type in declaration before ‘;’ token
If I change line 25 to:
ordered_non_unique<member<B, int, &B::n> >
It compiles fine. Any help would be much appreciated. Thanks.
I'm not quite sure, if this is what you are looking for, but you can change line 25 to:
ordered_non_unique<member<A, int, &A::m> >
This is compiling on gcc 4.4.
Regards Lars.