Suppose you have a namespace
approvedParams {
std::string s1 = "my_string_input_1";
std::string s2 = "my_string_input_2";
}
Outside the scope of approvedParams there exists a function myfun(std::string parm1)
Is it possible to constrain myfun signature to only accept fields of type std::string from the approvedParams namespace?
That is:
myfun("my_string_input_1") will not compile.
myfun(approvedParams::s1) will compile.
I was considering an implementation with enum. However I ultimately want use approvedParams::s1 and s2 when I am parsing key-value configuration files. enum must be of an integral type. I am not interested in adding another unnecessary layer with map<int,std::string> to connect the enum integers with std::string.
The type of s1 and s2 do not carry information about the namespace they were declared in.
You could rather easily wrap a custom type though.
namespace approvedParams
{
struct keytype { std::string val; };
keytype s1 = { "my_string_input_1" };
keytype s2 = { "my_string_input_2" };
}
void approvedParams( approvedParams::keytype );
Create an enum of approved parameter values
enum approvedParams {
val1 = 0,
val2, ...
};
And just create an array with the string using these indexes
std::string[] approvedParamValues = { "my_string_input_1", ... };
Here's my take at it, reusing #DrewDormann's idea of a wrapper type but in a way that actually enforces its usage.
The idea is basically a variant of the named constructor idiom, but only with static variables instead of fully-fledged factory functions (does this pattern have a name?).
// Declaration in .h
class ApprovedParam
{
public:
static const ApprovedParam foo;
static const ApprovedParam bar;
const std::string& value() const { return m_value; }
private:
std::string m_value;
ApprovedParam(const char* value) : m_value(value) {}
ApprovedParam(std::string&& value) : m_value(std::move(value)) {}
ApprovedParam(const std::string& value) : m_value(value) {}
// IMPORTANT: the user must not be able to default construct an ApprovedParam
ApprovedParam() = delete;
};
// Definitions in .cpp
const ApprovedParam ApprovedParam::foo = "foo";
const ApprovedParam ApprovedParam::bar = "bar";
Now the user can copy/move/assign ApprovedParam objects but he has only a limited set of (immutable) instances to choose from and he will not be able to create completely new ones.
Related
I have a class that for some reasons needs to store a pair (say int,double) for each key, but whose interface only makes public one of the two values of the pair (int). One implementation may be
using namespace std;
class Foo {
public:
map<string,int> const & get() const {return external;}
void doStuff(string const & str) {
external.at(str);
internal.at(str);
}
private:
map<string,int> external;
map<string,double> internal;
};
The drawback is that doStuff has double lookup.
Another way is to store map<string,pair<int,double>> allin but then the accessor returning the whole map requires a copy.
The last way, of course, is to make the accessor more atomic by accessing a single key with a return allin.at(key).first;, which seems the best way but it breaks the interface I would like to provide.
I wonder, is there a way to avoid the double lookup in the "external/internal" version?
Another way could be to define a map entry with a private and a public value. Via a friend declaration the private value can be made visable to Foo class.
#include <iostream>
#include <string>
#include <map>
class Foo;
template<typename T1, typename T2>
struct my_map_entry
{
public:
my_map_entry()=default;
my_map_entry(T1 v, T2 pv)
{
value = v;
private_value = pv;
}
T1 value;
private:
T2 private_value;
friend class Foo;
};
class Foo {
public:
Foo(){
map["test"]=my_map_entry<int, double>(1, 2.0);
}
void doStuff(const std::string& str
{
auto entry = map.at(str);
std::cout<<"private_value: "<<entry.private_value<<std::endl;
}
std::map<std::string,my_map_entry<int, double>> map;
};
int main()
{
Foo test;
test.doStuff("test");
}
Given you just want the user to be able to retrieve the item, your get() method can be rewritten bearing that requirement in mind.
using namespace std;
class Foo {
public:
int *const get(string const &str) const {
auto it = map_.find(str)
return it == map_.end() ? nullptr : &it->first;
}
void doStuff(string const & str) {
map_.at(str);
}
private:
map<string,pair<int, double>> map_;
};
The idea is to return nullptr if the key was not found, or a pointer to the value if the key was found.
If instead you also want to be able to enumerate all the available ints, then you only have three choices:
Make your Foo class a map-like class, with its own iterators that wrap the ones from the inner map.
Use one of the available libraries to provide a view that helps you achieving the previous goal (like boost::transform_iterator)
As the other answer suggests, use a struct as the map's value and make one of its fields private, with possibly a conversion operator to int.
I have some structs with varying types and amounts of data members:
struct Foo
{
int a;
float b;
char c;
}
struct Bar
{
std::string a;
int b;
}
struct Baz
{
char a;
}
I want to fill these data members with values contained in an external file. Is there a general solution such that if I later add a new struct with different data members, I won't have to alter my code that's reading in the data? I'd prefer to keep any functionality independent of these structs, but my best idea at the moment is a polymorphic solution where each struct has a static method responsible for reading in its data.
C++ as of now doesn't have a way to reflect the content of a struct. This means that there is no truly generic way to read into any given struct (neither by name nor by index). However you might create some kind of meta-description which might result in less overhead than to rewrite the XML deserialization for each structure.
Such a meta-description could look like (requires C++17):
enum FieldType { String, Int, Float, Char };
struct AbstractField
{
FieldType const type;
const char * const name;
AbstractField(FieldType type, const char *name) : type(type), name(name) {}
virtual ~AbstractField() {}
virtual bool setValue(std::any & dest, const std::any & value) const = 0;
}
template <typename Struct, typename Type>
struct Field : public AbstractField
{
Type Struct::*const fieldPtr;
Field(FieldType type, const char *name, Type Struct::*fieldPtr)
: AbstractField(type, name), fieldPtr(fieldPtr)
{}
bool setValue(std::any & dest, const std::any & value) const override
{
Struct *realDest = std::any_cast<Struct>(& dest);
const Type *realValue = std::any_cast<Type>(& value);
if (realDest != nullptr && realValue != nullptr) {
realDest->*fieldPtr = *realValue;
return true;
}
return false;
}
}
// The following has to be redone for each structure
static const std::vector<const AbstractField *> metaFoo = {
new Field<Foo, int>(Int, "a", & Foo::a)),
new Field<Foo, float>(Float, "b", & Foo::b)),
new Field<Foo, char>(Char, "c", & Foo:c))
};
There could be added some extra logic to get this even fancier (type_id instead of the enum, templated functions that only take the name and the member pointer to create the Field instance, abstract factories for the individual structs, etc).
The reader could then set a value in the structure like this
std::any parseValue(const std::string & value, FieldType type);
bool setField(std::any &dest, const std::vector<const AbstractField*> &meta,
const std::string & fieldName, const std::string & value)
{
for (auto field : meta) {
if (field->name == fieldName) {
std::any value = parseValue(value, field->type);
return field->setValue(dest, value);
}
}
return false;
}
When combined with abstract factories for the structs (similar to what I've done for the fields) this allows to instanciate a whole tree of structures just from the meta-description.
I have a class that reads a script and stores variables and their respective types which I reference by name (string). The class has a templatized member method named get, which fetches the variable that matches the name parameter from one of the member tables, and needs to return data of the same type as the variable type it is assigned to. To better illustrate my question, suppose I have a simplified class such as:
class Script
{
public:
template <typename T>
T get(std::string name);
private:
//data stored in associative containers such as:
// std::map<std::string, int> int_data;
// std::map<std::string, bool> bool_data;
};
In the implementation file, the member method is specialized:
template <>
int Script::get(std::string name)
{
int value = retrieve_integer(name);
return value;
}
template <>
bool Script::get(std::string name)
{
bool value = retrieve_boolean(name);
return value;
}
I would like to call the class method like this without explicitly providing the type with script.get<int>("varName"):
Script script; // loads script and reads data
bool useVsync = script.get("useVsync"); // calls the bool specific get
int screenWidth = script.get("screenWidth"); // calls the int specific get
How would I do this without causing could not deduce template parameter T errors? I know that this should be possible, because I have used libraries that allowed such syntax.
As explained in comment, you may abuse of conversion operator:
class Script
{
public:
struct ValueProxy {
operator bool() const {
return script.bool_data[name];
}
operator int() const {
return script.int_data[name];
}
ValueProxy& operator= (bool b) {script.bool_data[name] = b;}
ValueProxy& operator= (int n) {script.int_data[name] = n;}
Script &script;
std::string name;
};
ValueProxy get(std::string name) {
return ValueProxy{*this, std::move(name)};
}
private:
//data stored in associative containers such as:
std::map<std::string, int> int_data;
std::map<std::string, bool> bool_data;
};
int main() {
Script script;
script.get("myBool") = true;
script.get("MyInt") = 42;
bool b = script.get("MyBool"); // true
int i = script.get("MyInt"); // 42
int j = script.get("MyBool"); // 0
}
Let's say my class has an integer data member:
class MyClass {
public:
MyClass();
private:
int my_int;
}
Now upon construction, I want to receive a data type, a name and a value, all codified as strings:
public MyClass(string type, string name, string value) { ... }
And based on type and name, assign that value to my data member on construction. Something similar to:
public MyClass(string type, string name, string value)
{
this->parse(type, name, value);
}
private parse(string type_, string name_, string value_)
{
if (type_=="int")
{
int* int_ = getDataMember(name_);
(*int_)=atoi(value_);
}
else ....
}
So now when i declared MyClass c("int","my_int","5"), c would be initialized with its my_int data member set to the value of 5.
The problem is I have no idea how to implement getDataMember(string name). But it would obviously return a pointer to its data member of the name "name".
While this isn't how C++ is supposed to be used, it isn't entirely impossible.
#include <string>
#include <map>
class MyClass {
public:
MyClass(const std::string& type, const std::string& name, const std::string& value);
private:
void parse(const std::string& type_, const std::string& name_, const std::string& value_);
template <typename T>
T* getDataMember(const std::string& name);
int my_int;
double my_double;
char my_char;
std::map<std::string, char*> members; //Map of strings to member memory locations
};
MyClass::MyClass(const std::string& type, const std::string& name, const std::string& value)
{
//List of members will have to be hardcoded
members["my_int"] = reinterpret_cast<char*>(&my_int);
members["my_double"] = reinterpret_cast<char*>(&my_double);
members["my_char"] = reinterpret_cast<char*>(&my_char);
this->parse(type, name, value);
}
template <typename T>
T* MyClass::getDataMember(const std::string& name) {
return reinterpret_cast<T*>(members[name]); //Will need to handle invalid names
}
void MyClass::parse(const std::string& type_, const std::string& name_, const std::string& value_)
{
if (type_=="int")
{
int* int_ = getDataMember<int>(name_);
(*int_)=atoi(value_.c_str());
}
}
int main(void) {
MyClass c("int","my_int","5");
return 0;
}
The idea is to keep a map to reference strings to member addresses. Accessing the map with the string will return the address of the member corresponding to that string. However, this map will have to be hardcoded when new members are introduced to the class. Also, the getDataMember function will have to handle cases where invalid names are passed into the class.
Inefficiencies
string comparisons are fundamentally slow. The comparisons occur
when you are inserting members into the map, when you are going
through your parse function trying to identify the type, and when
you searching through the map for the correct key.
Possible ways to get rid of hardcoding
Suppose there is a way to fill the map without hardcoding. That would involve knowing what data members are present in the class. Since there does not seem to be such a functionality in C++, we would have to parse the file, or at least the part of the file that contains the class. However, we need this to be done before the file is compiled. This leaves us with 2 options:
Do it at compile-time, which involves using preprocessor directives. Unfortunately, I have no idea of any way to utilize preprocessor directives to do so.
Program an external executable that parses files in your project/workspace to identify the data members of the class and proceed to append the filling of the member map in the class's constructor(s). i.e. Automate the map filling process through an external executable. We can then ensure that this external executable is always run whenever the project is build through pre-build events.
Conclusion
I think it's best to either find another approach to the problem you are trying to solve, or use a whole other language because it seems C++ was not built for this.
Factoring in what your real problem is
I believe the solution you are looking for is called deserialization.
class MyClass {
public:
void Deserialize(XMLParser xml);
private:
int my_int;
double my_double;
char my_char;
};
void MyClass::Deserialize(XMLParser xml) {
while(xml.ReadLine() != "MEMBERS"); //Advances the XML parser to the line that specifies the members
//Proceed to deserialize the members in order
//This requires the file to list the members in the correct order
my_int = atoi(xml.ReadLine().c_str());
my_double = atof(xml.ReadLine().c_str());
my_char = atoi(xml.ReadLine().c_str());
}
In a C++ project I'm working on, I need to keep track of a label. The label simply stores a std::string that is appended to results written to various files so that the results can be mapped to a particular phase of the implemented algorithms.
Here are the requirements of the mechanism for keeping track of the label:
All translation units need access to this label
Label must be able to be modified during runtime
Need to control access to the label via getter/setter functions
Always need exactly 1 label
This is not hard to implement. But, nonetheless, I'm raising the question here because I suspect this is something commonly done --- or, at least, very similar to things commonly done.
The best solution I can think of is to have a class such as the following, and then just include the interface everywhere:
class Label {
public:
static std::string get();
static int set(std::string s);
private:
static std::string label;
};
std::string Label::get() { return label; }
int Label::set(std::string s) {
if( /* OK to change to "s" */ ) {
label = s;
return 0;
}
return 1;
}
std::string Label::label = "";
Because there's always exactly 1 of these labels, it seems like there ought to be a better solution than creating a class. Any suggestions?
I'd tend to wonder whether there might not be more use for a broader class, something like:
template <class T>
class cond_write {
T val;
std::function<bool()> c;
public:
template <class Cond>
cond_write(T const &t, Cond c): val(t), c(c) {}
cond_write &operator=(T const &t) {
if (c())
val=t;
return *this;
}
operator T() const { return val; }
};
Then you'd instantiate it with (in your case) std::string, and a lambda for the condition under which a write can happen.
Instead of get and set, you'd just assign to it, or use it as a T (std::string, in your case). For example:
cond_write<std::string> label("Initial label", []() { return whatever(); });
// equivalent to label.set("This might be the new label");
label="This might be the new label";
// equivalent to std::string new_label = label.get();
std::string new_label=label;
I see no need for a class here and recommend using free functions and a namespace. You have the same scoping semantics but without all of the decorations such as static. They also allow you to keep internals private just as you would with a class. A few minor changes and your code ends up like the following.
Header
namespace Label
{
std::string get();
// only require a copy when necessary and allow rvalues.
int set(const std::string& s);
};
Implementation
namespace // unnamed namespace is generally recommended over using static
{
std::string label;
}
std::string Label::get() { return label; }
int Label::set(const std::string& s)
{
if( /* OK to change to "s" */ )
{
label = s;
return 0;
}
return 1;
}