I'm getting a C++ compiler error that I don't understand and haven't been able to find
a fix or an explanation for. Here is a code snippet demonstrating the problem.
#include <iostream>
template<class T>
class A {
public:
A(int n) {data = new T[n]; }
const T &operator()(int i) const {return data[i];}
protected:
T *data;
};
template<class T>
class B : public A<T> {
public:
B(int n) : A<T>(n) {}
T &operator()(int i) {return this->data[i]; }
//const T &operator()(int i) const {return this->data[i];} // fixes problem
};
template<class T, int N>
class C : public B<T> {
public:
C() : B<T>(N) {}
private:
};
template<class T>
void doOp(const T &v) {
std::cout << v(0) << std::endl;
}
void templateTest()
{
C<double, 3> c;
c(0) = 5;
std::cout << c(0) << std::endl;
doOp(c);
}
If I un-comment the line in class B, the code compiles and executes correctly but I
don't understand why defining this operator function in class B is any different from
the definition in class A.
Thanks for the help.
Bill
The problem is that doOp() is invoking a non-const member function through a reference to const.
If you uncomment the commented line, a viable const member function will be found, and overload resolution will pick that version of the call operator.
Without uncommenting that line, the inherited version of the call operator is not found because it is being hidden by the overloaded call operator in the subclass.
To illustrate the problem of name hiding with a simpler example, consider the following program:
struct X
{
void foo() { }
};
struct Y : X
{
void foo(int) { }
};
int main()
{
Y y;
y.foo(42); // OK
y.foo(); // ERROR! Name hiding...
}
The compiler here won't be able to resolve the call to y.foo(), because X::foo() is being hidden by Y::foo() here.
To fix the problem, you could add a using declaration in Y:
struct X
{
void foo() { }
};
struct Y : X
{
using X::foo;
// ^^^^^^^^^^^^^
void foo(int) { }
};
int main()
{
Y y;
y.foo(42); // OK
y.foo(); // OK
}
Now both function calls are correctly resolved. In your program, you could add a similar using declaration for operator () of the base class:
template<class T>
class B : public A<T> {
public:
B(int n) : A<T>(n) {}
T &operator()(int i) {return this->data[i]; }
using A<T>::operator();
// ^^^^^^^^^^^^^^^^^^^^^^^
};
Related
I have a templated class on some object T. T defines two member functions bar and foo
template<class T>
class A {
public:
void f() {
t_.bar();
t_.foo();
}
private:
T t_;
};
Now I would like be able to tell A (ideally at compile time), to call either foo or bar, but not both. So the idea is to tell A at construction time which member function of T to call.
The solution I have currently in place is to pass a callable void callMember(const T& t) { return t.foo(); } in A's constructor to at runtime call the right member, but I'm wondering if there is a better solution?
You can add a bool template parameter to A that tells it which member function of T to call, and then use a constexpr if on that parameter in the body of f:
template<class T, bool Choice>
class A {
public:
void f() {
if constexpr(Choice) // doesn't strictly have to be constexpr
// if T defines both bar and foo
t_.bar();
else
t_.foo();
}
private:
T t_;
};
Now for some type like:
struct S {
void bar() { std::cout << "bar"; }
void foo() { std::cout << "foo"; }
};
you can do:
A<S, true> a;
a.f(); // calls S::bar
A<S, false> b;
b.f(); // calls S::foo
Here's a demo.
I assume its Ok to have instantiations of A be of different type depending on which method is called. If that is the case I suggest to choose between two types rather than two methods.
Say X is the type with the two methods, then you can do this:
struct X {
void foo() {}
void bar() {}
};
struct Xfoo {
X x;
void foobar() { x.foo(); }
};
struct Xbar {
X x;
void foobar() { x.bar(); }
};
Now the template is:
template<class T>
class A {
public:
void f() {
t_.foobar();
}
private:
T t_;
};
And you either instantiate A<Xfoo> or A<Xbar> rather than A<X>.
I suppose you have more than just one type X, then Xfoo and Xbar can be parametrized on the type to be wrapped.
I'm trying to implement a sort of static polymorphism by means of the CRTP and requires clauses.
What I want to achieve is to call a possibly overriden function in a function taking a reference to the CRTP base class.
I made it work with GCC 10 and 11 with the following approach:
#include <iostream>
template<typename T>
class Base
{
public:
void f() const requires T::IsOverridden
{ static_cast<T const *>(this)->f(); }
void f() const
{ std::cout << "Fallback f()" << std::endl; }
};
class A : public Base<A>
{
public:
static constexpr bool IsOverridden = true;
public:
void f() const
{ std::cout << "Overridden f()" << std::endl; }
};
class B : public Base<B> {};
template<typename T>
void f(Base<T> const &x)
{ x.f(); }
int main()
{
A const a;
B const b;
f(a);
f(b);
return 0;
}
However, Clang 11 doesn't like this piece of Code:
test.cpp:7:30: error: no member named 'IsOverridden' in 'A'
void f() const requires T::IsOverridden
~~~^
test.cpp:14:18: note: in instantiation of template class 'Base<A>' requested here
class A : public Base<A>
^
test.cpp:7:30: error: no member named 'IsOverridden' in 'B'
void f() const requires T::IsOverridden
~~~^
test.cpp:24:18: note: in instantiation of template class 'Base<B>' requested here
class B : public Base<B> {};
^
Which compiler is right?
Note: I'm using a boolean member to signal overriding because I want it to work with classes nested in template classes and that was the only way I came up with in that case.
I'm posting what I ended up using in case it is useful for somebody else.
I didn't like using a member variable, which I could easily misspell, to signal that the function was overridden.
Instead I used a defaulted std::false_type NTTP for the base-class function, and a std::true_type NTTP for the overloads, so that they can be detected with a requires-expression:
#include <iostream>
#include <type_traits>
template<typename T>
class Base
{
public:
template<std::false_type = std::false_type{}>
requires requires(T const x) { x.template f<std::true_type{}>(); }
void f() const
{ static_cast<T const *>(this)->f(); }
template<std::false_type = std::false_type{}>
void f() const
{ std::cout << "Fallback f()" << std::endl; }
};
class A : public Base<A>
{
public:
template<std::true_type = std::true_type{}>
void f() const
{ std::cout << "Overridden f()" << std::endl; }
};
class B : public Base<B> {};
template<typename T>
void f(Base<T> const &x)
{ x.f(); }
int main()
{
A const a;
B const b;
f(a);
f(b);
return 0;
}
GCC 11 accepts the terser syntax template<std::true_type = {}>, but GCC 10 and CLang 12 require the longer template<std::true_type = std::true_type{}>.
Trying to allow make_unique on a class with private ctor I came into the following strange difference between two cases:
Case 1 - empty ctor - compiles
class A {
int _i;
A(): _i(7) {}
public:
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
struct enablePrivateCtor : public A {
using A::A;
};
return std::make_unique<enablePrivateCtor>(std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
int main() {
auto a = A::create();
a->doIt();
}
Output:
7
Case 2 - non-empty ctor - doesn't compile
class A {
int _i;
A(int i): _i(i) {} // <- change 1, ctor getting int
public:
// no change here!
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
struct enablePrivateCtor : public A {
using A::A;
};
return std::make_unique<enablePrivateCtor>(std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
int main() {
auto a = A::create(7); // <- change 2, sending 7
a->doIt();
}
Compilation Error:
unique_ptr.h: error: calling a private constructor of class 'enablePrivateCtor'
Why the 1st one - with the empty ctor - is OK, while the 2nd - the non-empty ctor - is not?
The default constructor is never inherited. Therefore, the first enablePrivateCtor generates a default constructor, which calls the base class default constructor.
When you inherit a constructor (as in the second case), the new constructor has the same access level as the inherited one. So since A::A(int) is private, so too will be enablePrivateCtor::enablePrivateCtor(int). So you won't be able to construct with it.
If you need to have a private constructor be able to be called indirectly (through make_unique/emplace/etc), then you need to use a private key type. Like this:
class A;
class A_key
{
A_key() = default;
A_key(int) {} //Prevent `A_key` from being an aggregate.
friend class A;
};
class A {
int _i;
public:
A(int i, A_key): _i(i) {}
// no change here!
template<typename... T>
static std::unique_ptr<A> create(T&&... t)
{
return std::make_unique<A>(std::forward<T>(t)..., A_key{});
}
void doIt() const {
std::cout << _i << std::endl;
}
};
...
auto ptr = A::create(7);
A a(7, A_key{}); //Does not compile, since you're not a friend.
A_key is publicly copyable, but it is not publicly default constructible. So non-private code can pass them around, but non-private code cannot create them.
The difference is that enablePrivateCtor automatically gets a default constructor (which is allowed to call A::A).
It doesn't automatically get an integer conversion constructor: add
enablePrivateCtor(int i) : A(i) {}
and see it work.
The code you posted has undefined behavior.
In particular, you allocate an enablePrivateCtor then delete an A.
A better way than this is to use a key type.
class A {
int _i;
A(): _i(7) {}
class construction_token_t {
explicit construction_token_t(int) {}
friend class A;
};
static auto ctor_token() {
return construction_token_t(0);
}
public:
template<class...Args>
A( construction_token_t, Args&&...args ):A(std::forward<Args>(args)...){}
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
return std::make_unique<A>(ctor_token(), std::forward<T>(t)...);
}
void doIt() const {
std::cout << _i << std::endl;
}
};
We create a token which can grant another class the right to access our private ctor. The only one who can create this token is our class.
We then pass it to make_unique.
An alternative is to use the factory lambda pattern.
template<class F>
struct factory_lambda_t {
F f;
template<class T>
operator T() const { return f(); }
};
template<class F>
factory_lambda_t<std::decay_t<F>>
factory( F&& f ) { return {std::forward<F>(f)}; }
In C++14 this requires move/copy ctors to be public, but in C++17 it doesn't.
class A {
int _i;
A(): _i(7) {}
public:
template<typename... T>
static std::unique_ptr<A> create(T&&... t) {
return std::make_unique<A>(factory([&]{
return A(std::forward<T>(t)...);
}));
}
void doIt() const {
std::cout << _i << std::endl;
}
};
which I think is pretty slick.
This may result in eliding constructors completely in some cases. In others, a single move occurs.
I need a static analyzer that will find uninitialized variables members/variables... of a templated class type.
Can any analyzer do this? I tried clang/cppcheck and a couple of others with no luck.
Here is my test code:
enum class ViewMode
{
One = 1,
Two = 2,
Three = 3,
Four = 4
};
class TestClass {
public:
TestClass() {}
};
template<typename T, bool C = std::is_copy_constructible<T>::value>
class TemplateTest
{
public:
TemplateTest() {}
TemplateTest(const T& value)
: value_(value)
{}
TemplateTest(const TemplateTest&) = delete;
TemplateTest(TemplateTest<T, C>&& rhs)
: value_(std::move(rhs.value_))
{}
TemplateTest(T&& value)
: value_(std::move(value))
{}
private:
T value_;
};
class StaticAnalysisTest {
public:
StaticAnalysisTest() {}
void DoSomething() {
}
private:
ViewMode viewMode_; //this uninitialized warning is found
TemplateTest<ViewMode> viewMode2_; //this one is not
};
I have further distilled the problem to:
class Foo
{
private:
int m_nValue;
public:
Foo() {};
Foo(int value) : m_nValue(value) {}
int GetValue() { return m_nValue; }
};
class Bar
{
public:
Bar(){}
void DoSomething() {
Foo foo;
}
};
This does not generate an unitialized variable warning, but when I comment out:
//Foo(int value) : m_nValue(value) {}
it does
Thank you for evaluating Cppcheck. A warning is given for the second example, in case you add the --inconclusive flag, for example:
class Foo
{
private:
int m_nValue;
public:
Foo() {};
explicit Foo(int value) : m_nValue(value) {}
int GetValue() const
{
return m_nValue;
}
};
class Bar
{
public:
Bar() {}
static void DoSomething() {
Foo foo;
}
};
The output from Cppcheck
$ cppcheck --enable=all --inconclusive uninitmembervar.cpp
[uninitmembervar.cpp:6]: (warning, inconclusive) Member variable 'Foo::m_nValue' is not initialized in the constructor.
I want a type A that will yield its hidden datum to an object of type T but hide the datum from everyone else. My C++ compiler happens to be GCC 4.4, but that shouldn't matter. Why won't this work?
#include <iostream>
template <class T> class A {
private:
int n1;
public:
friend class T;
A(const int n0 = 0) : n1(n0) {}
};
class B {
public:
int f(const A<B> a) const { return a.n1; }
B() {}
};
int main() {
const A<B> a(5);
const B b;
const int m = b.f(a);
std::cout << m << "\n";
return 0;
}
Incidentally, this works fine, except that it fails to hide the datum:
#include <iostream>
template <class T> class A {
private:
int n1;
public:
int n() const { return n1; }
A(const int n0 = 0) : n1(n0) {}
};
class B {
public:
int f(const A<B> a) const { return a.n(); }
B() {}
};
int main() {
const A<B> a(5);
const B b;
const int m = b.f(a);
std::cout << m << "\n";
return 0;
}
Does C++ really not allow a friend class to be specified at compile time as a template parameter? Why not? If not, then what alternate technique should I use to hide the datum? (One would prefer a compile-time technique if possible.)
What is my misunderstanding here, please?
(I see some answers to related questions here and here, but either they don't answer my particular question or I fail to understand that they do so. At any rate, maybe I am using the wrong technique altogether. Though I remain interested in why the friend class T fails, what I really want to know is how to hide the datum, whether with a friend or by other means.)
Thanks.
Your compiler is simply too old. C++11 allows you to declare template parameters as friends.
ยง11.3 [class.friend] p3
A friend declaration that does not declare a function shall have one of the following forms:
friend elaborated-type-specifier ;
friend simple-type-specifier ;
friend typename-specifier ;
If the type specifier in a friend declaration designates a (possibly cv-qualified) class type, that class is declared as a friend; otherwise, the friend declaration is ignored.
And it even contains an example of a template parameter as a friend:
class C;
// [...]
template <typename T> class R {
friend T;
};
R<C> rc; // class C is a friend of R<C>
R<int> ri; // OK: "friend int;" is ignored
C++03 sadly has no way to do this, however you can simply friend a single free function and let that act as "glue" code that takes the data from one class and passes it to the other. Another way might be the passkey pattern.
I don't know the standardese behind your error (refer to Xeo's answer), but I did find a workaround for C++03.
Instead of making T a friend, make one of T's member functions a friend:
#include <iostream>
template <class T> class A {
private:
int n1;
public:
friend int T::getN1(const A& a) const;
A(const int n0 = 0) : n1(n0) {}
};
class B {
public:
int f(const A<B> a) const { return getN1(a); }
B() {}
private:
int getN1(const A<B>& a) const {return a.n1;}
};
class C {
public:
int f(const A<B> a) const { return getN1(a); }
C() {}
private:
// Error, n1 is a private member of A<B>
int getN1(const A<B>& a) const {return a.n1;}
};
int main() {
const A<B> a(5);
const B b;
const int m = b.f(a);
std::cout << m << "\n";
return 0;
}
Alternatively, you can make a nested class/struct of T be a friend of A. This may be more convenient if there are several private members of A that you want T to have access to.
#include <iostream>
template <class T> class A {
private:
int n1;
public:
friend class T::AccessToA;
A(const int n0 = 0) : n1(n0) {}
};
class B {
public:
int f(const A<B> a) const { return AccessToA::getN1(a); }
B() {};
private:
friend class A<B>;
struct AccessToA
{
static int getN1(const A<B>& a) {return a.n1;}
};
};
class C {
public:
int f(const A<B> a) const { return AccessToA::getN1(a); }
C() {};
private:
friend class A<C>;
struct AccessToA
{
// Error, n1 is a private member of A<B>
static int getN1(const A<B>& a) {return a.n1;}
};
};
int main() {
const A<B> a(5);
const B b;
const int m = b.f(a);
std::cout << m << "\n";
return 0;
}