I'm currently looking at some code that uses instances of both of the following types of maps:
std::map<std::string, const Foo>;
std::map<std::string, Foo>;
where the implementation of Foo is not relevant. As a result, all of the functions that take as input an instance of either of these two have two implementations of them: one for the const Foo version and the other for the non-const Foo version.
My question is this: is it possible to create something (like a class derived from std::map, for example) using templates that will allow me to essentially encapsulate both versions of the types above as one?
Edit: I know I can probably use SFINAE to only have to write one version of each of the relevant functions, but I'm wondering if there's a way to implement something a little bit further "upstream."
I apologize if my question doesn't make sense - I'm not exactly sure how to word it in a nice way.
A function that can accept both the const and non const versions of your map could be implemented in this manner:
template <typename T_foo>
T_foo do_something_with_map(std::map<std::string, T_foo> & map)
{
std::cout << map["m"].i_ << std::endl;
return map["m"];
}
int main()
{
std::map<std::string, const Foo> m1;
Foo f1(1);
m1.emplace("m", f1);
std::map<std::string, Foo> m2;
const Foo f2(2);
m2.emplace("m", f2);
auto res1 = do_something_with_map(m1);
auto res2 = do_something_with_map(m2);
}
With an example Foo:
class Foo {
public:
Foo() = default;
Foo(int i)
: i_(i)
{}
int i_;
};
Related
I have a class like this one:
struct Example
{
std::unique_ptr<int> pointer_member;
};
I'd like the type of pointer_member to be std::unique_ptr<int const> const when manipulating instances of Example const, and std::unique_ptr<int> when manipulating instances of Example.
The best solution I could think of so far involves templates, but it's really boilerplaty and not very usable (because the template arguments propagate to the code working with Example):
template <bool is_const>
struct Example
{
std::unique_ptr<std::conditional_t<is_const, int const, int>> pointer_member;
};
Also here, nothing prevents me from using Example<false> const instances and it's really annoying.
Any idea of how to achieve this in a better way?
Encapsulation allows to control modifiable-ness (aka constness) of members:
#include <memory>
struct Example {
const int& get() const {
return *pointer_member;
}
int& get() {
return *pointer_member;
}
private:
std::unique_ptr<int> pointer_member = std::make_unique<int>(42);
};
int main(){
const Example ex1;
const int& const_ref = ex1.get();
Example ex2;
ex2.get() = 123;
}
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";
}
}
I have a function that takes a vector-like input. To simplify things, let's use this print_in_order function:
#include <iostream>
#include <vector>
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<int> printme = {100, 200, 300};
std::vector<int> order = {2,0,1};
print_in_order(order, printme);
}
Now I have a vector<Elem> and want to print a single integer member, Elem.a, for each Elem in the vector. I could do this by creating a new vector<int> (copying a for all Elems) and pass this to the print function - however, I feel like there must be a way to pass a "virtual" vector that, when operator[] is used on it, returns this only the member a. Note that I don't want to change the print_in_order function to access the member, it should remain general.
Is this possible, maybe with a lambda expression?
Full code below.
#include <iostream>
#include <vector>
struct Elem {
int a,b;
Elem(int a, int b) : a(a),b(b) {}
};
template <typename vectorlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme) {
for (int i : order)
std::cout << printme[i] << std::endl;
}
int main() {
std::vector<Elem> printme = {Elem(1,100), Elem(2,200), Elem(3,300)};
std::vector<int> order = {2,0,1};
// how to do this?
virtual_vector X(printme) // behaves like a std::vector<Elem.a>
print_in_order(order, X);
}
It's not really possible to directly do what you want. Instead you might want to take a hint from the standard algorithm library, for example std::for_each where you take an extra argument that is a function-like object that you call for each element. Then you could easily pass a lambda function that prints only the wanted element.
Perhaps something like
template<typename vectorlike, typename functionlike>
void print_in_order(std::vector<int> const & order,
vectorlike const & printme,
functionlike func) {
for (int i : order)
func(printme[i]);
}
Then call it like
print_in_order(order, printme, [](Elem const& elem) {
std::cout << elem.a;
});
Since C++ have function overloading you can still keep the old print_in_order function for plain vectors.
Using member pointers you can implement a proxy type that will allow you view a container of objects by substituting each object by one of it's members (see pointer to data member) or by one of it's getters (see pointer to member function). The first solution addresses only data members, the second accounts for both.
The container will necessarily need to know which container to use and which member to map, which will be provided at construction. The type of a pointer to member depends on the type of that member so it will have to be considered as an additional template argument.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
private:
const Container * m_container;
MemberPtr m_member;
};
Next, implement the operator[] operator, since you mentioned that it's how you wanted to access your elements. The syntax for dereferencing a member pointer can be surprising at first.
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// Dispatch to the right get method
auto operator[](const size_t p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To use this implementation, you would write something like this :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
virtual_vector<decltype(printme), decltype(&Elem::a)> X(printme, &Elem::a);
print_in_order(order, X);
}
This is a bit cumbersome since there is no template argument deduction happening. So lets add a free function to deduce the template arguments.
template<class Container, class MemberPtr>
virtual_vector<Container, MemberPtr>
make_virtual_vector(const Container & p_container, MemberPtr p_member_ptr)
{
return{ p_container, p_member_ptr };
}
The usage becomes :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
If you want to support member functions, it's a little bit more complicated. First, the syntax to dereference a data member pointer is slightly different from calling a function member pointer. You have to implement two versions of the operator[] and enable the correct one based on the member pointer type. Luckily the standard provides std::enable_if and std::is_member_function_pointer (both in the <type_trait> header) which allow us to do just that. The member function pointer requires you to specify the arguments to pass to the function (non in this case) and an extra set of parentheses around the expression that would evaluate to the function to call (everything before the list of arguments).
template<class Container, class MemberPtr>
class virtual_vector
{
public:
virtual_vector(const Container & p_container, MemberPtr p_member_ptr) :
m_container(&p_container),
m_member(p_member_ptr)
{}
// For mapping to a method
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == true, const size_t> p_index) const
{
return ((*m_container)[p_index].*m_member)();
}
// For mapping to a member
template<class T = MemberPtr>
auto operator[](std::enable_if_t<std::is_member_function_pointer<T>::value == false, const size_t> p_index) const
{
return (*m_container)[p_index].*m_member;
}
private:
const Container * m_container;
MemberPtr m_member;
};
To test this, I've added a getter to the Elem class, for illustrative purposes.
struct Elem {
int a, b;
int foo() const { return a; }
Elem(int a, int b) : a(a), b(b) {}
};
And here is how it would be used :
int main() {
std::vector<Elem> printme = { Elem(1,100), Elem(2,200), Elem(3,300) };
std::vector<int> order = { 2,0,1 };
{ // print member
auto X = make_virtual_vector(printme, &Elem::a);
print_in_order(order, X);
}
{ // print method
auto X = make_virtual_vector(printme, &Elem::foo);
print_in_order(order, X);
}
}
You've got a choice of two data structures
struct Employee
{
std::string name;
double salary;
long payrollid;
};
std::vector<Employee> employees;
Or alternatively
struct Employees
{
std::vector<std::string> names;
std::vector<double> salaries;
std::vector<long> payrollids;
};
C++ is designed with the first option as the default. Other languages such as Javascript tend to encourage the second option.
If you want to find mean salary, option 2 is more convenient. If you want to sort the employees by salary, option 1 is easier to work with.
However you can use lamdas to partially interconvert between the two. The lambda is a trivial little function which takes an Employee and returns a salary for him - so effectively providing a flat vector of doubles we can take the mean of - or takes an index and an Employees and returns an employee, doing a little bit of trivial data reformatting.
template<class F>
struct index_fake_t{
F f;
decltype(auto) operator[](std::size_t i)const{
return f(i);
}
};
template<class F>
index_fake_t<F> index_fake( F f ){
return{std::move(f)};
}
template<class F>
auto reindexer(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return v[f(i)];
});
};
}
template<class F>
auto indexer_mapper(F f){
return [f=std::move(f)](auto&& v)mutable{
return index_fake([f=std::move(f),&v](auto i)->decltype(auto){
return f(v[i]);
});
};
}
Now, print in order can be rewritten as:
template <typename vectorlike>
void print(vectorlike const & printme) {
for (auto&& x:printme)
std::cout << x << std::endl;
}
template <typename vectorlike>
void print_in_order(std::vector<int> const& reorder, vectorlike const & printme) {
print(reindexer([&](auto i){return reorder[i];})(printme));
}
and printing .a as:
print_in_order( reorder, indexer_mapper([](auto&&x){return x.a;})(printme) );
there may be some typos.
Say a class Foo has two dependencies (Bar and Baz), and that it is an error to construct a Foo without providing both of them. Constructor injection makes it easy to guarantee at compile time that this is done:
class Foo
{
public:
Foo(const std::shared_ptr<Bar>& bar, const std::shared_ptr<Baz>& baz);
// (don't get hung up on the type of pointer used; it's for example only)
};
But let's say Foo also needs two doubles:
class Foo
{
public:
Foo(const std::shared_ptr<Bar>& bar, const std::shared_ptr<Baz>& baz,
double val1, double val2);
};
Now there is a problem; it would be really easy for the caller to accidentally transpose val1 and val2 and create a runtime bug. We can add a Params struct to allow named initialization and preclude this:
class Foo
{
public:
struct Params
{
std::shared_ptr<Bar> bar;
std::shared_ptr<Baz> baz;
double val1;
double val2
};
Foo(const Params& params);
};
// ...
std::shared_ptr<Foo> MakeDefaultFoo()
{
Foo::Params p;
p.bar = std::make_shared<Bar>();
p.baz = std::make_shared<Baz>();
p.val1 = 4.0;
p.val2 = 3.0;
return std::make_shared<Foo>(p);
}
But now we have the problem that the caller might forget to populate one of the fields in Params, which would not be detectable until runtime. struct initialization syntax or an initializer list would make it impossible to forget a field, but then we're back to relying on position!
Is there some trick that makes it possible to have the best of both worlds--compiler-enforced mandatory arguments that are assigned by name instead of position?
Just have a simple wrapper may work:
template <typename Tag, typename T>
struct Argument {
explicit Argument( const T &val );
T get() const;
};
class Foo {
public:
struct Val1Tag;
struct Val2Tag;
typedef Argument<Val1Tag,double> Val1;
typedef Argument<Val2Tag,double> Val2;
Foo( Val1 v1, Val2 v2 );
};
Foo foo( Foo::Val1( 1.0 ), Foo::Val2( 2.3 ) );
Now types are explicit and you cannot swap them without getting compiler error.
Very curious to see what cdhowie is tinkering with, but in the meantime, a simple wrapper with different types might solve some problems:
struct Val1 {
explicit Val1(double v) : v(v) { }
operator double() const { return v; }
double v;
};
// copy for Val2
class Foo
{
public:
Foo(const std::shared_ptr<Bar>& bar, const std::shared_ptr<Baz>& baz,
Val1 val1, Val2 val2);
};
This way you can't mix them up, since you'll have to construct a Foo like:
Foo foo(bar, baz, Val1{3.0}, Val2{7.0});
It's a bunch of extra typing to make sure the types are different, and you definitely have to make sure you make the constructor explicit (or it defeats the point), but it helps.
Something like this (untested)
template <typename tag, typename t>
struct param
{
explicit param(t vv)
: v(vv) {}
param(const param& p)
: v(p.v) {}
t v;
};
struct one{}; struct two {};
using paramone = param<one, double>;
using paramtwo = param<two, double>;
void somefunc (paramone p1, paramtwo p2)
{ ... };
void somefunc (paramtwo p2, paramone p1)
{ somefunc(p1, p2); }
// using it
somefunc (2, 3); // bad
somefunc (paramone(2), paramtwo(3)); // good
somefunc (paramtwo(3), paramone(2)); // also good
When using a std::pair or std::map, we need to use "first" or "second" to access data. But the two variable name do not have clear meanings of what it really store for other co-workers that did not write this code. So if we can make aliases for "first" or "second", it would enhance much readability.
For example, the following code
static const std::map<std::string, std::pair<std::string, PFConvert>> COMM_MAP =
{ // keyword-> (caption, function)
{std::string("1"), {std::string("Big5 to Utf16LE"), &FileConvert_Big5ToUtf16LE}},
{std::string("2"), {std::string("Utf16LE to Utf8"), &FileConvert_Utf16LEToUtf8}},
{std::string("3"), {std::string("Utf8 to Big5"), &FileConvert_Utf8ToBig5}}
};
auto iterToExe = COMM_MAP.find(strTransType);
iterToExe->second.second();
The iterToExe->second.second(); has a truly bad readability.
So I try to use inherit to give aliases as following
template<typename PFComm>
class CCommContent : public std::pair<std::string, PFComm>
{
public:
std::string &strCaption = std::pair<std::string, PFComm>::first;
PFComm &pfComm = std::pair<std::string, PFComm>::second;
};
template<typename PFComm>
class CCommPair : public std::pair<std::string, CCommContent<PFComm>>
{
public:
std::string &strPattern = std::pair<std::string, CCommContent<PFComm>>::first;
CCommContent<PFComm> commContent = std::pair<std::string,CCommContent<PFComm>>::second;
};
template<typename PFComm>
class CCommMap : public std::map<std::string, CCommContent<PFComm>, std::less<std::string>, std::allocator<CCommPair<PFComm>>>
{};
But this comes to an another issue: I have to declare all the ctors, though i could call the base ctors, but it still not seems to be a smart method. I Just want to make aliases.
A simple way is to use macro ...... but it bypass the type checking. when using a nested structure, it may be a nightmare when debug.
Any advice or discussion would be appreciated.
Why not simply use your own struct with your own element names?
struct MyPair {
std::string strCaption;
PFComm pfComm;
};
With C++11 you can easily create new objects of it:
MyPair{std::string("Big5 to Utf16LE"), &FileConvert_Big5ToUtf16LE}}
And if you define your own operator<, you can have std::set work as a map:
bool operator<(const MyPair& a, const MyPair& b) {
return a.strCaption < b.strCaption;
}
typedef std::set<MyPair> MyPairMap;
Naturally, you can nest your custom structs to form more complex nested pairs, although in your case you might want to consider a flat triplet instead:
struct CommMapEntry {
std::string number;
std::string caption;
PFComm pfComm;
};
bool operator<(const MyPair& a, const MyPair& b) {
return a.number<b.number;
}
static const std::set<CommMapEntry> COMM_MAP;
How about some typedefs and accessor functions?
using CommEntry = std::pair<std::string, PFConvert>;
std::string const & getCaption(CommEntry const & e) { return e.first; }
PFConvert const & getFunction(CommEntry const & e) { return e.second; }
Now you can say:
auto it = COMM_MAP.find(strTransType);
if (it != COMM_MAP.end())
{
auto & c = getCaption(it->second);
auto & l = getLabel(it->second);
// ...
}
If you later change the details of the type, you just have adapt the accessor functions.
well, in c++11, we can using base::base in a derive class to use the base ctors. But note that vs2013 DO NOT compliant this. g++4.8 do.