Using non-const variable inside constexpr? - c++

Consequently to a previous question about const/non-const with ternary operator, is the following test function ok regarding to the C++11 standard :
template<bool UseConst> class MyClass
{
public:
constexpr bool test()
{
return (UseConst) ? (_constvar) : (_var);
}
protected:
int _var;
static const int _constvar;
}
The whole problem, is that _constvar is const, and _var is non-const. I would have to access these 2 data depending on the template parameter through the same function, and I would like to have a compile-time function when I use const.
Do the test() function satisfy my requirements ?

You could use SFINAE in order to "specialize" your test function. In other words, you could do something like the following:
template<bool true_false>
struct true_type
{
static char value;
};
template<>
struct true_type<false>
{
static char value[2];
};
template<bool UseConst> class MyClass
{
private:
constexpr int pre_test(const char arg) { return _constvar; }
int pre_test(char (&)[2]) const { return _var; }
public:
constexpr int test()
{
return pre_test(true_type<UseConst>::value);
}
protected:
int _var;
static const int _constvar;
};
Now, when you call MyClass::test, if UseConst is false, test will degrade to a run-time function, but when UseConst is true, you will get a compile-time function.

Related

Why are static members and static constant members different in initialization?

class Test
{
private:
static int data;
public:
static constexpr int MAX{ 10 }; // OK
public:
int getData() const { return data; }
void setData(int rhs) { data = rhs; }
};
int Test::data{};
I have code like above.
Why are static members and static constant members different in initialization?
Is it just a difference in grammar?
That's because in C++17, constexpr implies inline, allowing in-line definitions with initialisers. A more fair comparison would be with static inline int data{};, which looks the same.
A constexpr variable has to have an initialiser (presumably so it can be used in constant expressions). Before C++17, this means that you have to write:
class Test
{
private:
static int data;
public:
static constexpr int MAX{ 10 };
public:
int getData() const { return data; }
void setData(int rhs) { data = rhs; }
};
constexpr int Test::MAX;
int Test::data{};
to be able to ODR-use MAX (essentially "take the address of"/"bind a reference to") since inline static data members didn't exist. This is also similar for constexpr and non-constexpr static data members.

Template class spezialisation missing member

I wanted to create a simple template class having a member variable ret. For some reason my MSVC 2010 compiler complains, that there is no declared variable named ret in Converter<double>. I'm really clueless, why?
template<typename M>
struct Converter {
M ret;
void operator()(const int& value) {
throw std::exception("Not implemented!");
}
};
template<>
struct Converter<double> {
void operator()(const int& value) {
ret=value;
}
};
int main() {
Converter<int> x;
}
This is another class (there is no inheritance or any other depenency here):
template<>
struct Converter<double> {
double ret;
void operator()(const int& value) {
ret=value;
}
};
I know this is already marked solved, but I thought I should just clarify this further.
Converter<double> and Converter<int> are different separate classes, so ret would not be defined in your double variation until you declare it as one of its members.
Regardless, it appears what you're trying to achieve is inheritance, which can be done in a similar way:
template<typename M>
struct AbstractConverter { // you could call it 'Converter' too, and it'll work as you expect
M ret;
virtual void operator()(const int& value) {
throw std::exception("Not implemented!");
}
//or
virtual void operator(const int &value) = 0; //pure virtual
// will not compile if someone wants to use it directly
};
template<>
struct Converter<double> : public AbstractConverter<double>{
void operator()(const int& value) { // we implement the operator here
ret=value;
}
};

static constexpr function different than global?

I cannot understand why static constexpr behaves differently then global constexpr. What am I doing wrong? Compiler error is not particularly helpful:
prog.cpp:20:17: error: ‘static constexpr int Bar::foo(const char*)’ called in a constant expression
B = Bar::foo(s)
^
prog.cpp:20:17: error: enumerator value for ‘B’ is not an integer constant
code is as follows:
#include <iostream>
constexpr int foo(const char* v)
{
return v[0];
}
struct Bar
{
static constexpr int foo(const char* v)
{
return v[0];
}
static constexpr const char* s = "abc";
enum
{
A = ::foo(s),
B = Bar::foo(s)
};
};
int main()
{
int a[Bar::A];
a[0] = Bar::A;
}
This is because the enum is part of the class declaration, whereas the definitions of the functions inside the class are logically deferred until after the class declaration. This means that as far as the enum is concerned, it can't see the definition of B::foo, and therefore it can't use a call to it as a constant expression. You can see this by putting the enum after the class:
#include <iostream>
constexpr int foo(const char* v)
{
return v[0];
}
struct Bar
{
static constexpr int foo(const char* v)
{
return v[0];
}
static constexpr const char* s = "abc";
};
enum Enum
{
A = ::foo(Bar::s),
B = Bar::foo(Bar::s)
};
which gives no error.

working with std::bitset

There is a class definition and some bool functions which test some attributes
class MemCmd
{
friend class Packet;
public:
enum Command
{
InvalidCmd,
ReadReq,
ReadResp,
NUM_MEM_CMDS
};
private:
enum Attribute
{
IsRead,
IsWrite,
NeedsResponse,
NUM_COMMAND_ATTRIBUTES
};
struct CommandInfo
{
const std::bitset<NUM_COMMAND_ATTRIBUTES> attributes;
const Command response;
const std::string str;
};
static const CommandInfo commandInfo[];
private:
bool
testCmdAttrib(MemCmd::Attribute attrib) const
{
return commandInfo[cmd].attributes[attrib] != 0;
}
public:
bool isRead() const { return testCmdAttrib(IsRead); }
bool isWrite() const { return testCmdAttrib(IsWrite); }
bool needsResponse() const { return testCmdAttrib(NeedsResponse); }
};
The question is how can I set NeedsResponse to true or false prior to calling needsResponse()
Please note that attributes is of type std::bitset
UPDATE:
I wrote this function:
void
setCmdAttrib(MemCmd::Attribute attrib, bool flag)
{
commandInfo[cmd].attributes[attrib] = flag; // ERROR
}
void setNeedsResponse(bool flag) { setCmdAttrib(NeedsResponse, flag); }
But I get this error:
error: lvalue required as left operand of assignment
From the comments:
There are two problems here
Data members that are const must be initialized in the class constructor.
If the members are const there is no way to change them later.
So, initialize (at least) the members that are supposed to have a constant value. Remove const from the members you intend to change later.

pointer to const member function typedef

I know it's possible to separate to create a pointer to member function like this
struct K { void func() {} };
typedef void FuncType();
typedef FuncType K::* MemFuncType;
MemFuncType pF = &K::func;
Is there similar way to construct a pointer to a const function? I've tried adding const in various places with no success. I've played around with gcc some and if you do template deduction on something like
template <typename Sig, typename Klass>
void deduce(Sig Klass::*);
It will show Sig with as a function signature with const just tacked on the end. If to do this in code it will complain that you can't have qualifiers on a function type. Seems like it should be possible somehow because the deduction works.
You want this:
typedef void (K::*MemFuncType)() const;
If you want to still base MemFuncType on FuncType, you need to change FuncType:
typedef void FuncType() const;
typedef FuncType K::* MemFuncType;
A slight refinement showing how to do it without a typedef.
In a deduced context like the following, you can't use a typedef.
template <typename Class, typename Field>
Field extract_field(const Class& obj, Field (Class::*getter)() const)
{
return (obj.*getter)();
}
applied to some class with a const getter:
class Foo {
public:
int get_int() const;
};
Foo obj;
int sz = extract_field(obj, &Foo::get_int);
Another more direct way to do it (avoiding using and typedefs) is this:
#include <iostream>
class Object
{
int i_;
public:
int j_;
Object()
: Object(0,0)
{}
Object(int i, int j)
: i_(i),
j_(j)
{}
void printIplusJplusArgConst(int arg) const
{
std::cout << i_ + j_ + arg << '\n';
}
};
int main(void)
{
void (Object::*mpc)(int) const = &Object::printIplusJplusArgConst;
Object o{1,2};
(o.*mpc)(3); // prints 6
return 0;
}
mpc is a const method pointer to Object.