How to initialize a template class with a non constant value - c++

I have a template class that needs I need to set the size of using the size of a vector. what is the best way to achieve this? below is a simplified version, I will link to the full class if you need to see it.
template<int maxParams>
class ParameterChangeHandler
{
public:
inline ParameterChangeHandler()
{
//Do Stuff
};
//More Inline Methods that use maxparams and paramBitArray
protected:
unsigned char paramBitArray[(((maxParams)+((8) - 1)) & ~((8) - 1)) / 8]
};
int main()
{
std::vector<int> myVectorOfParameters = { 1,2,3,4,5 };
//This is OK
//ParameterChangeHandler<10> paramChangeHandler;
//This is what I want
ParameterChangeHandler<myVectorOfParameters.size()> paramChangeHandler
}
This is for an audio application that I am building using the Wwise SDK, Here is a link to the actual class that is giving me the issue
AkFXParameterChangeHandler

What you want isn't possible. Here's what you can do. Pass myVectorOfParameters.size() as an argument to the constructor and use std::vector/std::basic_string instead of unsigned char array so you don't need a constant expression for the size.
#include <vector>
#include <cstddef>
class ParameterChangeHandler
{
public:
ParameterChangeHandler(std::size_t const max_size)
: paramBitArray(max_size) // or reserve and push_back as needed
{
// Do Stuff
};
protected:
std::vector<unsigned char> paramBitArray;
};

Related

How to match a C-style array in Google Mock

Given the following example
#include <gmock/gmock.h>
#include <gtest/gtest.h>
#include <stdint.h>
using namespace ::testing;
class Tested
{
public:
virtual void setArray(const uint32_t[3]) {};
};
class Tested_mock: public Tested
{
public:
MOCK_METHOD1(setArray, void(const uint32_t[3]));
};
class TestRunner: public ::testing::Test
{
public:
StrictMock<Tested_mock> t;
};
TEST_F(TestRunner, test)
{
uint32_t a[3] = {1UL, 2UL, 3UL};
EXPECT_CALL(t, setArray(_)).With(ElementsAreArray(a));
t.setArray(a);
}
i don't understand why i'm not able to compile this snippet while changing the argument to uint32_t* works. Does Gmock have a problem with fixed-size-array arguments ?
You could find the compilation output here https://pastebin.com/72b4iYqs
Late to party but I had the same issue.
The problem is that the testing framework also wants to know the size of the actual array to check if it's the same as expected.
In the end I ended up defining my own Matcher that takes the size as an argument:
MATCHER_P2(FixedSizeArrayMatches, expected, elements, "")
{
return memcmp(arg, expected, elements * sizeof(expected[0])) == 0;
}
This can then be used like this:
EXPECT_CALL(t, setArray(FixedSizeArrayMatches(a, 3));

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 initialize lookup-table static std::array, a private member of a class, defined with constexpr length based on bit length of int

Trying to create a class which acts as a tool to amplify/attenuate some value based on lookup tables.
Foo.h
#ifndef FOO_H
#define FOO_H
#include <array>
#include <limits>
class Foo
{
public:
Foo();
~Foo();
static double applySomeFoo(double f, unsigned int amplify_by);
private:
static constexpr int m_BITS_IN_INT {std::numeric_limits<int>.digits};
static std:array<double, m_BITS_IN_INT> m_fooFactors /***?** Don't know what to put here! */;
// **?** Tried {{}}, {} and nothing and {{...}} and {...} and {{{}}} then scratched head...
};
#endif
Foo.cpp
#include <assert>
#include "Foo.h"
double Foo::applySomeFoo(double f, unsigned int amplify_by)
{
assert(amplify_by < Foo::m_BITS_IN_INT);
return (f * Foo::m_fooFactors.at(amplify_by));
}
// FOO
Foo::Foo() : /**?** Don't know what to put here! */
{
// ctor
// Populate the lookup table
int i {0};
for(auto &x : Foo::m_fooFactors)
{
x = static_cast<double>(2 ^ i++);
}
}
Foo::~Foo()
{
// dtor
}
I'm new to C++.
It fails to compile and I don't really understand how to instantiate so I can then populate the static array with values since it has a compile-time-variable length.
So the question boils down to;
Q. How can I ensure m_fooFactors is an instantiation of an array of zeros of the known fixed-length so I can then populate it in the class constructor?
This EXAMPLE is a toy re. the m_fooFactors calculation, the actual calc is more complex, but gives you a flavor of my usage of the std::array as lookup-table.
I am using GCC and trying to make C++11 code.
I would be grateful for any help.

Cannot declare array of strings as class member

I could not declare an array of strings in my class. Below my class definition:
class myclass{
public:
int ima,imb,imc;
string luci_semaf[2]={"Rosso","Giallo","Verde"};
};
and my main file
#include <iostream>
#include <fstream>
#include "string.h"
#include <string>
using namespace std;
#include "mylib.h"
int main() {
return 0;
}
Why do I get the following warnings / error?
You have two problems: The first is that you can't initialize the array inline like that, you have to use a constructor initializer list. The second problem is that you attempt to initialize an array of two elements with three elements.
To initialize it do e.g.
class myclass{
public:
int ima,imb,imc;
std::array<std::string, 3> luci_semaf;
// Without C++11 support needed for `std::array`, use
// std::string luci_semaf[3];
// If the size might change during runtime use `std::vector` instead
myclass()
: ima(0), imb(0), imc(0), luci_semaf{{"Rosso","Giallo","Verde"}}
{}
};
You can not initialize data member.
You can write like this:
class myclass{
public:
myclass() {
luci_semaf[0] = "Rosso";
luci_semaf[1] = "Giallo";
luci_semaf[2] = "Verde";
}
private:
int ima,imb,imc;
string luci_semaf[3];
};
You can assign the values of the array in the Сonstructor
You're declaring an array of size 2 but providing 3 strings!
Try storing the elements in vector of strings, in c++ vectors are used more often.
class myclass{
public:
int ima,imb,imc;
std::vector<std::string> strings;
myclass() {
strings.push_back("blabla");
}
};

Initialize static variables declared in header

I'm changing the class implementation of a large class for a company project that has several static variables declared as private members of the class. There are many arrays and structs declared in the class header that utilize these static variables. I now need to assign the static data members values from my main function somehow. I tried assigning the static variables through the constructor but the header is declared prior to the constructor call so that wasn't possible.
For example, if I have
class Data
{
private:
static unsigned int numReadings = 10;
static unsigned int numMeters = 4;
unsigned int array[numMeters];
}
I would want to change it such that I could set numReadings and numMeters from my main function somehow, so it will allow all of my arrays and structs that utilize numMeters and numReadings to be initialized properly.
Is there a way to do this in C++? Of course I could always change my class design and set these in the constructor somehow but I'd like to avoid that if I can as it will take quite a long time.
You cannot do it in the main function, but you can do it in the main.cpp file:
// Main.cpp
#include <iostream>
#include "T.h"
using namespace std;
int T::a = 0xff;
int main()
{
T t; // Prints 255
return 0;
}
// T.h
#pragma once
#include <iostream>
using namespace std;
class T {
public:
T() { cout << a << endl; }
private:
static int a;
};
Have you tried making them public and accessing them with Data::numReadings = 10?
UPDATE:
#include <cstdlib>
using namespace std;
/* * */
class Asdf
{
public:
static int a;
};
int Asdf::a = 0;
int main(int argc, char** argv) {
Asdf::a = 2;
return 0;
}
Regardless of the accessibility of these variables, you need to define and initialize the static members outside the class definition:
// header
class Data
{
private:
static unsigned int numReadings;
static unsigned int numMeters;
unsigned int array[numMeters]; //<=see edit
};
// class implementation file
unsigned int Data::numReadings = 10;
unsigned int Data::numMeters = 4;
This is part of the implementation of the class and shouldn't be in the header (ODR rule).
Of course, if you want to access these variables (which are shared among all instances of the class) from outside, you need to make them public, or better, foresee and accessor.
Edit:
As the question is formulated around the static issue, I didn't notice the variable length array : this is not standard c++, although some compilers might accept it as a non-standard extension.
To do this properly, you should define a vector and initialize it at construction:
class Data
{
public:
Data ();
private:
static unsigned int numReadings;
static unsigned int numMeters;
vector<unsigned int> mycontainer; //<=for dynamic size
};
Data::Data() : mycontainer(numMeters) { } // initialize object with right size