Why does C++11 fail to treat two template typenames T == U in constructor in a template class? - class

I could not find a short and better title. :(
Suppose I have a simple C++11 template class definition as below:
#include <utility>
template <typename T>
class A
{
public:
T v;
A(){};
template <typename U>
A(const A<U>& a); // copy ctor
A(A<T>&& a); // move ctor
};
template <typename T>
template <typename U>
A<T>::A(const A<U>& a) // copy ctor
{
v = a.v;
}
template <typename T> // move ctor
A<T>::A(A<T>&& a)
{
v = std::move(a.v); // although moving PODs does not make sense in my example
}
Now, my C++11 code uses the above C++11 class as follows:
int main()
{
A<char> a;
A<float> b(a); // okay
A<char> c(a); // gcc output is as below:
// error: use of deleted function 'constexpr A<char>::A(const A<char>&)'
// note: 'constexpr A<char>::A(const A<char>&)' is implicitly declared
// as deleted because 'A<char>' declares a move constructor or move
// assignment operator
return 0;
}
It gives the error use of deleted function 'constexpr A<char>::A(const A<char>&)'.
However, it compiles and runs properly when I am not using any move semantics in the class definition as below:
#include <utility>
template <typename T>
class A
{
public:
T v;
A(){};
template <typename U>
A(const A<U>& a);
// A(A<T>&& a); // removed move ctor
};
template <typename T>
template <typename U>
A<T>::A(const A<U>& a)
{
v = a.v;
}
My questions are:
Why the gcc compiler is treating the template <typename U> in copy ctor differently in the two situations?
Why does it fail to treat typenames T == U in the presence of move ctor?
Why do I need to explicitly write yet another template
function template <typename T> A<T>::A(const A<U>& a) when using
move ctor?

You haven't written a copy constructor. From [class.copy] in the C++11 standard:
A non-template constructor for class X is a copy constructor if its first parameter is of type X&, const X&, volatile X& or const volatile X&, and either there are no other parameters or else all other parameters have default arguments (8.3.6).
(I see no provision for a template constructor to be called a copy constructor)
and consequently
If the class definition does not explicitly declare a copy constructor, one is declared implicitly
The difference between the two examples is whether or not you have a move constructor:
If the class definition declares a move constructor or move assignment operator, the implicitly declared copy constructor is defined as deleted; otherwise, it is defined as defaulted (8.4)

Defining the move constructor disabled the copy constructor. What you want is a converting constructor, which as the name implies, converts its argument to the type of the class. If your copy/move constructors don't do anything special, either omit or default them. To explain the final piece of your confusion, the reason you can omit the template arguments in your fake copy constructor is because of the injected class name. Meaning that wherever you see A, it's silently substituted for A<T>. I've included it for clarity.
template <typename T>
class A
{
public:
T v;
A() = default;
template <typename U>
A<T>(const A<U>& a);
A(const A<T>& a) = default;
A(A<T>&& a) = default;
};

Related

Accessing private member values with external template function

I'm a noob of c++, I'm trying to use a template function to get the private members inside a class because there are two types of parameters.
What I wrote is like:
template <typename Type>
Type const& Get(Type const& value)
{
return value;
}
class Event{
public:
Event(int const InputYear, int const InputMonth, int const InputDay, char const* InputContent, char const* InputNa me = "None")
:Year(InputYear), Month(InputMonth), Day(InputDay), Content(InputContent), Name(InputName)
{
}
~Event();
private:
int Year;
int Month;
int Day;
char* Content;
char* Name;
friend Type const& Get(Type const& value);
};
I don't know if my definition of friend is correct, if not could someone tell me how to use such template to access the private members?
The specification tells us that under certain circumstances (in this case explicit template instantiations), the usual access checking rules are not applied.
12 The usual access checking rules do not apply to names used to specify explicit instantiations. [ Note: In
particular, the template arguments and names used in the function declarator (including parameter types,
return types and exception specifications) may be private types or objects which would normally not be
accessible and the template may be a member template or member function which would not normally be
accessible. — end note ]
Thus, we can use this property to make a generic getter to a private member.
template <auto Event::* Member>
struct Getter {
friend auto &get(Event &e) { return e.*Member; }
};
template struct Getter<&Event::Year>;
auto &get(Event &e);
Event event{2021, 12, 24, "some event description"};
int year = get(event); // 2021

how to use template "inheritance" to avoid boilerplate code when binding C++ to python with pybind11

I managed to bind template definitions doing
py::class_<T<a>>(m, "Ta")
py::class_<T<b>>(m, "Tb")
...
where T is the template class and a and b typenames defining the template. But the problem I have tells me that this is not the really good way to expose these template definitions, because now I am forced to duplicate code for all the functions and parameters of the template class T:
py::class_<T<a>>(m, "Ta")
.def(py::init<string, string>())
.def("do_smthg", &T<a>::do_sthg)
...;
py::class_<T<b>>(m, "Tb")
.def(py::init<string, string>())
.def("do_smthg", &T<b>::do_sthg)
...;
when class T itself for instance has do_smthg, that I would then expect to have to define only once. I tried to browse the doc and the web, but I failed to find the right pointer.
You may just create a simple helper function that instantiates a list of templates, like following:
template <typename x, typename ... Tail, typename ModT>
void ApplyTemplate(ModT & m, std::vector<std::string> names) {
py::class_<T<x>>(m, names.at(0))
.def(py::init<string, string>())
.def("do_smthg", &T<x>::do_sthg)
;
names.erase(names.begin());
if constexpr(sizeof...(Tail) > 0)
ApplyTemplate<Tail...>(m, names);
}
Now call this function within module context with all possible arguments to template:
PYBIND11_MODULE(example, m) {
ApplyTemplate<a, b>(m, {"Ta", "Tb"});
}
If for some reason your T template is not available within ApplyTemplate context then you may pass it as a template <typename> typename argument:
template <template <typename> typename T, typename x, typename ... Tail, typename ModT>
void ApplyTemplate(.....
Instead of function you can also use a simple macro:
PYBIND11_MODULE(example, m) {
// Define macro
#define MY_CLASS(param, name) \
py::class_<T<param>>(m, name) \
.def(py::init<string, string>()) \
.def("do_smthg", &T<param>::do_sthg) \
;
// Use macro
MY_CLASS(a, "Ta");
MY_CLASS(b, "Tb");
// Remove macro
#undef MY_CLASS
}

Copy or Move Constructor for a class with a member std::mutex (or other non-copyable object)?

class A
{
private:
class B
{
private:
std::mutex mu;
A* parent = NULL;
public:
B(A* const parent_ptr): parent(parent_ptr) {}
B(const A::B & b_copy) { /* I thought I needed code here */ }
};
public:
B b = B(this); //...to make this copy instruction work.
// (Copy constructor is deleted, need to declare a new one?)
};
I have a class B that is basically a thread-safe task queue. It contains a deque, a mutex, and a condition_variable. It facilitates a consumer/producer relationship between any two threads that are started by the class A. I have simplified the code as much as possible.
The problem starts with having a mutex as a member: this deletes the default copy constructor. This just means I can construct using B(this) but I am not able to construct and copy using B b = B(this), which is what I need to do in the last line in order to give class A members of class B. What is the best way to solve this problem?
The simple solution is to use a std::unique_ptr<std::mutex> in your class, and initialize it with std::make_unique(...) where ... are your std::mutex constructor arguments, if any.
This will allow for move but not copy. To make it copyable, you would need to initialize the copy in the copy constructor, assuming copies should have their own lock.
If copies should share that lock, then you should use a std::shared_ptr. That is copyable and movable.
Thanks to Doug's suggestion of using std::unique_ptr, my class is pretty simply now and does what I want. Here's my final solution.
class A
{
private:
class B
{
private:
std::unique_ptr<std::mutex> mu_ptr = std::make_unique<std::mutex>()
A* parent = NULL;
public:
B(A* const parent_ptr) : parent(parent_ptr) {}
};
public:
B b = B(this); // This now works! Great.
};

Why isn't my static member function recognised across assemblies?

I have a helper assembly which includes a function to identify object types:
namespace Util
{
using namespace System;
public ref class CastingHelpers
{
public:
template < class T, class U >
static System::Boolean isinst(U u);
static bool Test() {return true;}
};
}
...but for some reason, when I try and use it in a gui application which references the assembly:
Util::CastingHelpers::Test();
Util::CastingHelpers::isinst<SomeClass^>(someInstance);
..gives me an error:
2>.\DataProcessor.cpp(161) : error C2039: 'isinst' : is not a member of 'Util::CastingHelpers'
Note that test works fine. Is this something to do with the fact that isinst uses generics?
You are not creating a generic function, you are creating a C++ template function which is not exported from the assembly.
Use the keyword generic instead of template to create .NET generic types and methods.
The template method is only visible by code that #includes its declaration.

Doxygen for C++ template class member specialization

When I write class templates, and need to fully-specialize members of those classes, Doxygen doesn't recognize the specialization - it documents only the generic definition, or (if there are only specializations) the last definition. Here's a simple example:
===MyClass.hpp===
#ifndef MYCLASS_HPP
#define MYCLASS_HPP
template<class T> class MyClass{
public:
static void foo();
static const int INT_CONST;
static const T TTYPE_CONST;
};
/* generic definitions */
template<class T>
void MyClass<T>::foo(){
printf("Generic foo\n");
}
template<class T>
const int MyClass<T>::INT_CONST = 5;
/* specialization declarations */
template<> void MyClass<double>::foo();
template<> const int MyClass<double>::INT_CONST;
template<> const double MyClass<double>::TTYPE_CONST;
template<> const char MyClass<char>::TTYPE_CONST;
#endif
=== MyClass.cpp ===
#include "MyClass.hpp"
/* specialization definitions */
template<>
void MyClass<double>::foo(){
printf("Specialized double foo\n");
}
template<> const int MyClass<double>::INT_CONST = 10;
template<> const double MyClass<double>::TTYPE_CONST = 3.141;
template<> const char MyClass<char>::TTYPE_CONST = 'a';
So in this case, foo() will be documented as printing "Generic foo," INT_CONST will be documented as set to 5, with no mention of the specializations, and TTYPE_CONST will be documented as set to 'a', with no mention of 3.141 and no indication that 'a' is a specialized case.
I need to be able to document the specializations - either within the documentation for MyClass<T>, or on new pages for MyClass<double>, MyClass<char>. How do I do this? Can Doxygen even handle this? Am I possibly doing something wrong in the declarations/code structure that's keeping Doxygen from understanding what I want?
I should note two related cases:
A) For templated functions, specialization works fine, e.g.:
/* functions that are global/in a namespace */
template<class T> void foo(){ printf("Generic foo\n"); }
template<> void foo<double>(){ printf("Specialized double foo\n"); }
This will document both foo<T>() and foo<double>().
B) If I redeclare the entire template, i.e. template<> class MyClass<double>{...};, then MyClass<double> will get its own documentation page, as a seperate class. But this means actually declaring an entirely new class - there is no relation between MyClass<T> and MyClass<double> if MyClass<double> itself is declared. So I'd have to redeclare the class and all its members, and repeat all the definitions of class members, specialized for MyClass<double>, all to make it appear as though they're using the same template. Very awkward, feels like a kludge solution.
Suggestions? Thanks much :)
--Ziv
Further seeking indicates that this issue was an open bug, fixed in Doxygen 1.8.10.
This bug appears to be fixed 3 weeks ago