Let's say I have the below class:
template <class Base>
struct Wrapper : public Base {
using Base::Base;
// ... add functionality ...
};
And I want some code to be executed during construction after constructors. I can't add a default constructor, because it won't be run when an inherited constructor is used. One idea is this:
template <class Base>
struct Wrapper : public Base {
bool _ = [this] {
// initialize ...
return true;
}();
using Base::Base;
};
This does work perfectly well as long as you place it as the last member, but it wastes memory.
Another way is:
#include <type_traits>
template <class T>
struct InitBlock {
InitBlock() {
static_cast<T*>(this)->init();
}
};
template <class Base>
struct Wrapper : public Base, private InitBlock<Wrapper<Base>> {
private:
template <class T>
friend struct InitBlock;
void init() {
// initialize ...
}
public:
using Base::Base;
};
Which is good, but a bit verbose. And there is nothing protecting init from being called again elsewhere. Also, if Wrapper adds members, this is called before those are initialized, so it's not ideal.
What is a better (safe and low on boilerplate) way of doing this?
As mentioned, we can use [[no_unique_address]] to avoid allocating memory for an empty class. It is honored by all major compilers, except for MSVC. MSVC has its own extension of [[msvc::no_unique_address]]. We wrap a macro around this, and it works fine:
#include <stdio.h>
#ifdef _MSC_VER
#define NO_UNIQUE_ADDRESS [[msvc::no_unique_address]]
#else
#define NO_UNIQUE_ADDRESS [[no_unique_address]]
#endif
template <class Base>
struct Wrapper : public Base {
private:
NO_UNIQUE_ADDRESS struct Init {} _ = [] {
puts("Wrapper init");
return Init{};
}();
public:
using Base::Base;
};
struct Foo {
int i;
Foo(int i) : i(i) {
printf("Foo(%d)\n", i);
}
};
int main() {
Wrapper<Foo> wfoo(42);
Foo foo(43);
static_assert(sizeof(wfoo) == sizeof(foo));
}
You still have to take care to place it after all other members to make sure they're initialized by the time we touch them, so it's not ideal.
See online
Related
I have stumbled upon something that I don't quite understand. I have a class hierarchy that uses private inheritance where each of the structs defines a different function call operator. Oddly enough, the function call operator from the topmost struct is available in the most derived struct, despite the fact that a using directive is only used in the first derived struct. A regular function foo, though, is not accessible there, as expected. Example:
#include <string>
#include <vector>
#include <iostream>
struct A {
void foo() {}
void operator()(bool) {
std::cout << "bool\n";
}
};
struct B : private A {
using A::foo;
using A::operator();
void operator()(std::string) {}
};
struct C : private B {
using B::operator();
void operator()(std::vector<int>) {}
};
struct D : private C {
using C::operator();
void operator()(std::vector<double>) {}
};
int main() {
D d{};
d(false); // <-- works!
//d.foo(); // <-- error: ‘void A::foo()’ is private within this context
return 0;
}
I happened upon this while trying to implement the C++17 overload object for use with boost::apply_visitor using pre-C++17 code. I solved it using recursive inheritance, where each object pulls in the function call operator of its direct base class like so:
template<typename T, typename... Ts>
struct visitor : private T, private visitor<Ts...> {
using T::operator();
using visitor<Ts...>::operator();
visitor(T func, Ts... tail) : T{ std::move(func) }, visitor<Ts...>{ std::move(tail)... } {}
};
template<typename T>
struct visitor<T> : private T {
using T::operator();
visitor(T func) : T{ std::move(func) } {}
};
template<typename... Ts>
visitor<Ts...> make_visitor(Ts&&... funcs) {
return visitor<Ts...>{ std::forward<Ts>(funcs)... };
}
I wanted to understand why all of the operators are available in the most derived object. That's how I came up with the above example. Compiler is g++ 11.1.0.
Can anyone enlighten me as to what's going on here?
As pointed out by others in comments, it turns out I just had an error in my thinking. The using pulls in all the operators available in the respective base class, including the ones that were imported by the base class itself, and therefore all the operators will be available in the bottommost object. foo, on the other hand, is just handed down to B.
How to use gmock to mock a template method (not a template class) for a class? Example a class like this, I want to mock this class, and this template method..
class A{
public:
template<EnumType ENUM_VALUE>
int getType(int val);
};
I know how to mock a class with non-virtual methods, or mock a templated class, but i dont know how to mock a non-templated class with a templated method..
First much better solution is to use the implementation of this function A::getType - maybe it does not have to be mocked? E.g.: if it just returns some value that is set in constructor - then just construct A in the way that is needed in your test case:
class A{
public:
A(int a) : a(a) {}
template<typename T>
int getType(int val)
{
return a + val;
}
private:
int a;
};
TEST(...)
{
A a(TYPE_VALUE_FOR_TEST);
...
}
If it cannot be done that way - then you might consider to have some instrumentation for UT that is switched with preprocessor macros:
#ifdef TESTING
namespace Testing
{
using std::pair<std::type_index, int> AGetTypeKey;
std::map<AGetTypeKey, int> AGetTypeExpectedValues;
template <typename T>
void expectAGetType(int inputValue, int expectedResult)
{
AGetTypeExpectedValues[AGetTypeKey(std::type_index(typeid(T)), inputValue)] = expectedResult;
}
template <typename T>
int getAGetType(int value)
{
return AGetTypeExpectedValues[AGetTypeKey(std::type_index(typeid(T)), inputValue)];
}
}
#endif
class A{
public:
A(int a) : a(a) {}
template<typename T>
int getType(int val)
{
#if TESTING
return Testing::getAGetType<T>(val);
#else
// your "normal" implementation
...
#endif
}
private:
int a;
};
// compiled with -DTESTING=1
#ifndef TESTING
#error ...
#endif
TEST(...)
{
Testing::expectAGetType<float>(EXPECTED_INPUT_VALUE,
TYPE_VALUE_FOR_FLOAT);
...
}
Regarding point-2 - of course all testing code should be carefully separated from "normal code" - e.g. in some separated header files.
It is worth to say that none of these solution is perfect - and this second solution might not be 100% reliable as you would test not real code but some testable version of it.
Maybe you should start from rethinking your design - as it seems the design was not completed with "design for testability" in mind.
I end up doing a relay to mock the method
E.g.
class MOCK_A{
public:
template<Enum ENUM_VALUE>
int getType(int val){
getType(val, ENUM_VALUE);
}
MOCK_METHOD1(getType, int(int val, Enum enum_value));
};
I have some code that is doing the following but I don't understand what the
using BaseTypeX::BaseTypeX is actually doing in this code. The rest of it I understand so please don't explain template specialization etc.
template<typename TReturn, typename... TArgs>
class ClassX<TReturn(TArgs...)> : public Internal::ClassXImpl<TReturn, TArgs...> {
public:
using BaseTypeX = Internal::ClassXImpl<TReturn, TArgs...>;
using BaseTypeX::BaseTypeX; // what is this doing exactly?
inline ClassX() noexcept = default;
// member function
template<class TThis, class TFunc>
inline ClassX(TThis* aThis, TFunc aFunc) {
this->bind(aThis, aFunc); // note bind is implemented in the ClassXImpl class
}
It means you inherit all the constructors of Internal::ClassXImpl<TReturn, TArgs...>. A simpler example might illustrate this better:
struct Foo
{
Foo(int);
Foo(int, double);
Foo(std::string);
};
struct Bar : Foo
{
using Foo::Foo;
};
int main()
{
Bar b1(42); // OK, Foo's constructors have been "inherited"
Bar b2(42, 3.14); // OK too
Bar b2("hello"); // OK
}
Without the using Foo::Foo, you would have to declare and define all the constructors in Bar, and call the respective Foo constructor in each one of them.
It means template class ClassX inherits its base's constructors. See here for a discussion on the topic.
I am trying to implement a generic hashlist class using templates and I am trying to inherit from the base class but getting lots of compile errors. Here is my code:
#ifndef BASEHASHLIST_H_
#define BASEHASHLIST_H_
#include <string>
#include <boost/unordered_set.hpp>
#include <iostream>
#include <boost/interprocess/sync/interprocess_semaphore.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
template <typename T>
class BaseHashList
{
private:
boost::interprocess::interprocess_semaphore m_semaphore;
protected:
boost::unordered_set<T> m_hsHashSet;
typename boost::unordered_set<T>::iterator m_hsIter;
public:
BaseHashList();
};
template <typename T>
BaseHashList<T>::BaseHashList():m_semaphore(1){}
#endif /* BASEHASHLIST_H_ */
And here is the class that is inheriting from the base class:
#ifndef ACCOUNTLIST_H_
#define ACCOUNTLIST_H_
#include "BaseHashList.h"
class AccountList : public BaseHashList<unsigned long>
{
public:
AccountList(std::string p_strFile, unsigned long p_ulMaxAccountNo);
~AccountList(void);
int m_iVersion;
std::string m_strFilePath;
private:
unsigned long m_ulMaxAccountNo;
};
#endif /* ACCOUNTLIST_H_ */
and here is the cpp file:
#include "AccountList.h"
AccountList::AccountList(std::string p_strFile, unsigned long p_ulMaxAccountNo)
: BaseHashList<unsigned long>::m_hsHashSet<unsigned long>(),
m_iVersion(0),
m_strFilePath(p_strFile)
{
m_ulMaxAccountNo = p_ulMaxAccountNo;
}
AccountList::~AccountList(){}
I am receiving a lot of compile time errors such as:
expected template-name before token '<'
expected '(' before token '<'
For such a simple task I spent couple of hours and I am super frustrated, does anybody see what I am doing wrong here?
This initaliser in AccountList's constructor looks wrong to me:
BaseHashList<unsigned long>::m_hsHashSet<unsigned long>()
You should initalise the members of BaseHashList inside a constructor of BaseHashList itself, one will always either explicitly or implicitly be called.
This example is simplified and similarly wrong:
struct A {
int bar;
};
struct B : A {
B() : A::bar(0) {}
};
(saying bar(0) would also be wrong there)
However you can get the desired behaviour:
struct A {
A() : bar(0) {}
int bar;
};
struct B : A {
B() {} // Implicitly calls A::A although we could have explicitly called it
};
The constructor of A gets called and given a chance to initalise its members here still.
When you inherit from a template class, you have to add the template instruction to the child class too :
template <typename T>
class A : public B<T>
You also have to add the template instruction before the definition of constructors and methods :
template <typename T>
A<T>::A() : B<T>() {...}
template <typename T>
A<T>::~A() {...}
Two-phase lookup question:
Is there a more synthetic way to write this code, i.e. avoiding all those using directives?
Something like using CBase<T>; is what I would like, but it is not accepted.
#include <iostream>
template <typename T>
class CBase
{
protected:
int a, b, c, d; // many more...
public:
CBase() {
a = 123; c = 0;
}
};
template <typename T>
class CDer : public CBase<T>
{
// using CBase<T>; // error, but this is what I would like
using CBase<T>::a;
using CBase<T>::b;
//...
public:
CDer() {
std::cout << a << this->c;
}
};
int main()
{
CDer<int> cd;
}
In my real code there are many more member variables/functions, and I was wondering if it is possible to write shorter code in some way.
Of course, using the this->c syntax does not solve the problem...
Thank's!
gcc 4.1
MacOS X 10.6
I reduced the testcase and then consider three options
template<typename T> struct Base { int a; };
Option 1
template<typename T> struct Der : Base<T> {
void f() {
int &ra = Der::a;
// now use ra
}
}
Option 2
template<typename T> struct Der : Base<T> {
void f() {
// use this->a instead
// or Der::a
}
}
Option 3
// use your using declarations
It doesn't look like most of those variables are parameterized. Does CBase use them all, or just a? If not, move them into a new non-template base of CDer.
Or, pack them all into a POD struct and then using CBase<T>::m_ints;.
High overhead solution: non-templated virtual base.
Not sure but worth a try: nest the definition of CDer inside CBase and then typedef it into namespace scope.