How do I declare a constant pair inside my header file - c++

#include <utility>
class C {
private:
const std::pair<int,int> corner1(1,1);
};
GCC reports error: expected identifier before numeric constant.
I need to construct the object on the moment of it's declaration since it's const, but I can't seem it get the right syntax.

I need to construct the object on the moment of it's declaration since it's const, but I can't seem it get the right syntax.
No, you can only initialize non-integral types - const or not (at least pre-C++11) in the constructor initializer list:
class C {
private:
const std::pair<int,int> corner1;
C() : corner1(1,1) {}
};
But it seems to me like you don't need to replicate the member in every instance, so I'd just make it static instead:
class C {
private:
static const std::pair<int,int> corner1;
};
//implementation file:
const std::pair<int,int> C::corner1(1,1);

If you pass -std=c++11 and you are using a more recent version of gcc, you can do this:
class C {
private:
const std::pair<int,int> corner1{1,1}; // Note curly braces
};

Related

Idiom for a C++11 enum with methods and static instances?

I'd like to do the following (which won't compile):
class Foo {
int value;
Foo(const int arg)
: value{arg}
{}
public:
static const Foo a{0};
static const Foo b{1};
static const Foo c{2};
Foo func(const Foo& foo) {...}
};
so that the the instances of Foo are strongly controlled (like in an enum) and so that I can write code like auto foo = Foo::a; and auto foo = Foo::a.func(Foo::b);
Unfortunately, the code won't compile under C++11 because the static instances have incomplete type.
Is there an idiom for this?
You can do it quite easily but you need to put the definitions of your constants outside the class:
class Foo {
int value;
// In C++17, you could make this constexpr.
Foo(const int arg)
: value{arg}
{}
public:
// in C++20, you could make these constinit.
static const Foo a;
static const Foo b;
static const Foo c;
};
// In C++11 these need to go in the source file to avoid linker errors.
// In C++17 you could make them inline and put them in the header.
// In C++20 you could make them constinit.
const Foo Foo::a = 0;
const Foo Foo::b = 1;
const Foo Foo::c = 2;
I wouldn't call this an elegant solution though. Particularly in C++11, these constants can't be inlined by the compiler because they need to go into the source file. This can have a significant impact on performance. So if you're going to do it, I would recommend using at least C++17, if not C++20.
Generally, C++ enums are meant to be integer constants and there is no support for getting the ordinal or name of an enum like there is in Java. An alternative approach is to use an enum class with no values (which defaults to values 0, 1, 2, ...) and then use them as indices inside of lookup tables.
Using a switch for properties can also do the trick:
enum class Axis : unsigned { X, Y, Z };
// in C++17, you could make this constexpr.
inline const char *nameOf(Axis axis)
{
switch (axis) {
case Axis::X: return "X";
case Axis::Y: return "Y";
case Axis::Z: return "Z";
}
}

How to define an implicit conversion for typedefs?

I want to have an automatic conversion from std::string into my type my_type, defined as
typedef std::pair<std::string,int> my_type;
such that the .first part of the converted my_type is the string and the .second part is always 0.
It should also work if one calls the function std::string fun(my_type x, ...) { return x.first; } with, say,
std::string s = "Hello"; fun(s, ...);.
I don't want to define a new class instead of my_type and also not to overload all of my functions if possible. I tried to wrap my head around how to use operator for this but I can't get my program to compile.
EDIT:
Since this doesn't seem to be possible without defining a custom struct or so, here is a workaround that I came up with, but I was hoping it can be achieved without defining a new class/struct. Thank you for saving me more time trying to do this, though.
class Element {
public:
Element() {};
Element(std::string s, int a) { name = s; value = a; };
Element(std::string s) { name = s; value = 0; };
...
std::string return_name() { return name; };
private:
std::string name;
int value;
};
std::string fun(Element x) { return x.return_name(); };
Calling std::string s = "Hello"; fun(s); works now automatically.
It is not possible to add new implicit conversions for existing classes, such as std::pair. Implicit conversions can only be member functions:
A non-explicit constructor that can be called with one argument. If there are more arguments, they must have default values.
operator T() const conversion operator.
And it is not possible to add new member functions to classes without changing class definition. This restriction is in place to prevent a function introduced at global or namespace scope from changing the semantics of your existing code.
What you can do instead is create a new class with a conversion constructor (a non-explicit constructor that can be called with one argument):
struct MyPair : std::pair<std::string, int> {
// In this class scope pair now refers to std::pair<std::string, int>.
MyPair(std::string const& a)
: pair(a, 0)
{}
MyPair(pair const& a)
: pair(a)
{}
};
The derivation from std::pair<std::string, int> makes it possible to pass MyPair where std::pair<std::string, int> is expected. And another constructor for converting std::pair<std::string, int> to MyPair.

Accessing type members in C++

Given an container such as a vector<int>
#include <vector>
using namespace std;
vector<int> v{1, 2, 3};
Why does it seem to be quite difficult to access the public type members such as iterator and const_iterator? As I understand it, these names are part of the class (not the object) and must be accessed via :: to specify the scope, but is there a reason to forbid v.const_iterator when v is known?
Example:
int f(v.iterator it) {
return *it;
}
// or
int g(v::iterator it) {
return *it;
}
A workaround would be using decltype as in:
int h(decltype(v)::iterator it) {
return *it;
}
But this approach does not even work in classes, as the following fails:
class A
{
public:
int h(decltype(x)::iterator it) {
return *it;
}
private:
vector<int> x;
};
Edit
Just a little sidenote.
As pointed out, the meaning of v.iterator would depend on the type of v at the point of usage (compile time) ignoring runtime polymorphism. But the same is true for static class members.
Example:
struct A
{
static const int x = 1;
};
struct B : public A
{
static const int x = 2;
};
void eval()
{
B b;
A& ar = b;
b.x; // 2
ar.x; // 1, even though ar refers to the same underlying object (by the base type)
}
As #Slava pointed out in comments, decltype(x) is the way to do it:
#include <vector>
using namespace std;
vector<int> v{1, 2, 3};
int f(decltype(v)::iterator it) {
return *it;
}
int g(decltype(v)::iterator it) {
return *it;
}
class A
{
private:
vector<int> x;
public:
int h(decltype(x)::iterator it) {
return *it;
}
};
The member access . operator and scope resolution operator :: may not be overloaded. And as you might deduce from the names, . is used to access members, while :: is used to access scope.
#include <iostream>
struct B {
class iterator { };
// no need for typename, compiler knows that we mean typedef B::iterator, as he can only find it
iterator iterator1;
// member named the same as class, ops!
int iterator;
// we need to use typename here, B::iterator is resolved as member
// iterator iteartor3;
typename B::iterator iterator2;
};
int main() {
B bobj;
// we access the member iterator inside b
bobj.iterator = 1;
// we declare object of B::iterator type
// we need to tell compiler that we want only types
typename B::iterator iterator;
// this will work too
typename decltype(bobj)::iterator iterator2;
// we declare a member pointer to the iterator member inside some B class
// no typename, as I want pointer to member, not pointer to... type
int B::* pointer = &B::iterator;
// this is just a pointer to the iterator specifically in bobj class
int * pointer2 = &bobj.iterator;
// foo(bar)
bobj.*pointer = 1;
// this will work as expected
int decltype(bobj)::* pointer3 = &B::iterator;
}
Also, there are no "type members" in C++ (at least I couldn't find them in C++ standard). Classes and enumerations and typedefs declarations declared in a class as members are called "nested types" or "nested classes".
Basically, C++ lets you get either values or types when you access them through ::. So MyType::AnotherType is fine as well as MyType::AValue. When you go through an instance with ., it only means it want to resolve a symbol which is a kind of a value (field, func, etc.). Hope that helps.

Initializing struct via member initialization list

So I'm learning C++ from Stephen Prata book and I want to do one exercise... So the problem is this:
I want to use a std::valarray inside a struct, inside a class like this:
class Wine
{
private:
struct Pair
{
std::valarray<int> valYear;
std::valarray<int> valBottlesNum;
};
int m_yearNum;
Pair m_numericData;
public:
Wine();
Wine(int, const int[], const int[]);
};
And initialize this via member initialization list:
Wine::Wine(int yearNum, const int year[], const int bottlesNum[])
: m_yearNum(yearNum),
m_numericData.valYear(yearNum, year),
m_numericData.valBottlesNum(yearNum, bottlesNum)
{}
But it just doesn't want to work. Somehow compiler does not like this "." to access members of a m_numericData struct in a initializer list.
I could just abandon Pair struct and do valYear and valBottlesNum as a simple class member variables and initilize them like this...
Wine::Wine(, int yearNum, const int year[], const int bottlesNum[])
: m_yearNum(yearNum), m_valYear(yearNum, year), m_valBottlesNum(yearNum, bottlesNum)
{}
but I really want to know how to solve this kinda stuff.
Thanks in adavnce!
You can move the individual initialisations into the body of the constructor:
Wine::Wine(int yearNum, const int year[], const int bottlesNum[])
: m_yearNum(yearNum)
{
m_numericData.valYear = std::valarray<int>(yearNum, year);
m_numericData.valBottlesNum = std::valarray<int>(yearNum, bottlesNum);
}
Alternatively, give Pair its own constructor.
The valarray constructor you're attempting to use takes a T const* to the data and an std::size_t argument indicating the number of array elements that the first argument points to. If you can use C++11, then change yearNum to std::size_t and you can use list-initialization, which in turn will aggregate initialize the Pair.
Wine::Wine(std::size_t yearNum, const int year[], const int bottlesNum[])
: m_yearNum(yearNum)
, m_numericData{{year, yearNum}, {bottlesNum, yearNum}}
{}
Live demo

Is there a default hash function for an unordered_set of a custom class?

I'm using a std::unordered_set for the first time and have a question about the hash function. As far as I understand, if you don't specify a hash function it will default to std::hash<Key>.
I have a mySet member in one of my classes:
typedef std::unordered_set<MyClass> USetType;
USetType mySet;
When I try to build, I get the following error:
error C2440: 'type cast' : cannot convert from 'const MyClass' to 'size_t'
Is it necessary to define a conversion function (to size_t) if you want to use unordered_set with a custom class? Is there any way to avoid writing your own hash function and just using the default?
If you don't specify your own hash functor as template argument, it will default to std::hash<MyClass>, which does not exist unless you define it.
Best define your own specialization of std::hash inside namespace std:
namespace std {
template <>
struct hash<MyClass>
{
typedef MyClass argument_type;
typedef std::size_t result_type;
result_type operator()(const MyClass & t) const
{
/* ..calculate hash value for t */
}
};
}
And make sure you include this code before the declaration of your hash. This way you can declare the hash simply as std::unordered_set<MyClass> with no need for further template arguments.
You didn't specify what MyClass looks like inside, but a typical situation is that your user-defined type simply consists of several simple-type members, for which a default hash function exists. In this case, you will probably want to combine the hash values for the individual types to a hash value for the entire combination. The Boost library provides a function called hash_combine for this purpose. Of course, there is no guarantee that it will work well in your particular case (it depends on the distribution of data values and the likelihood of collisions), but it provides a good and easy-to-use starting point.
Here is an example of how to use it, assuming MyClass consists of two string members:
#include <unordered_set>
#include <boost/functional/hash.hpp>
struct MyClass
{
std::string _s1;
std::string _s2;
};
namespace std {
template <>
struct hash<MyClass>
{
typedef MyClass argument_type;
typedef std::size_t result_type;
result_type operator()(const MyClass & t) const
{
std::size_t val { 0 };
boost::hash_combine(val,t._s1);
boost::hash_combine(val,t._s2);
return val;
}
};
}
int main()
{
std::unordered_set<MyClass> s;
/* ... */
return 0;
}
I'd like to expand on the answer given by jogojapan. As mentioned in a comment by CashCow on that answer, you also have to either overload the equality comparison operator (operator==) for MyClass or define a separate comparison function and provide it to the unordered_set. Otherwise, you will get another error message. For example, VS 2013 throws:
error C2678: binary '==' : no operator found which takes a left-hand operand of type 'const MyClass' (or there is no acceptable conversion)
Moreover, you can use lambda expressions instead of defining the hash and comparison functions. If you don't want to use Boost, then you can also handcraft a hash function. I understand, that you want to use some default function, but a compiler doesn't know how to calculate a meaningful hash for a custom class. However, you can use std::hash for the members of your class. If you put everything together, then your code could be written as follows:
class MyClass {
public:
int i;
double d;
std::string s;
};
int main() {
auto hash = [](const MyClass& mc){
return (std::hash<int>()(mc.i) * 31 + std::hash<double>()(mc.d)) * 31 + std::hash<std::string>()(mc.s);
};
auto equal = [](const MyClass& mc1, const MyClass& mc2){
return mc1.i == mc2.i && mc1.d == mc2.d && mc1.s == mc2.s;
};
std::unordered_set<MyClass, decltype(hash), decltype(equal)> mySet(8, hash, equal);
return 0;
}
Code on Ideone