This question already has answers here:
Why can templates only be implemented in the header file?
(17 answers)
Closed 4 years ago.
I'm trying to implement the iostream operators as a friend function to a variadic class template.
#include <utility>
#include <iostream>
template<typename... Args>
class StudentInformation {
public:
//friend class Student;
using Members = std::tuple<Args...>;
Members members;
const size_t numArgs{ sizeof...(Args) };
StudentInformation( Args&&... args ) : members{ std::make_tuple<Args...>( std::move( args )... ) } {}
const StudentInformation<Args...>& operator() ( Args... args ) {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
const StudentInformation<Args...> operator() ( Args... args ) const {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
friend std::ostream& operator<< ( std::ostream& out, const StudentInformation& c );
friend std::istream& operator>> ( std::istream& in, StudentInformation& c );
};
template<typename... T>
std::ostream& operator<<( std::ostream& out, const StudentInformation<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
out << std::get<idx>( c.members ) << " ";
return out;
}
template<typename... T>
std::istream& operator>>( std::istream& in, StudentInformation<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
in >> std::get<idx>( c.members );
return in;
}
And for some reason I'm still getting a linker error. Even when the overloads are defined in the header I'm still getting a linker error as if they were defined in a cpp file. Any thoughts?
Even when I try this approach: Declaring a prototype of the class first, then declaring prototypes of the overloaded operators, then declaring the class, then defining the friend overloaded operators:
#include <utility>
#include <iostream>
template<typename... Args>
class StudentInfo;
template<typename... Args>
std::ostream& operator<<( std::ostream& out, const StudentInfo<Args...>& c );
template<typename... Args>
std::istream& operator>>( std::istream& in, StudentInfo<Args...>& c );
template<typename... Args>
class StudentInfo {
public:
//friend class Student;
using Members = std::tuple<Args...>;
Members members;
const size_t numArgs{ sizeof...(Args) };
StudentInfo( Args&&... args ) : members{ std::make_tuple<Args...>( std::move( args )... ) } {}
const StudentInfo<Args...>& operator() ( Args... args ) {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
const StudentInfo<Args...> operator() ( Args... args ) const {
members = std::make_tuple<Args>( std::forward<Args>( args )... );
return *this;
}
friend std::ostream& operator<< ( std::ostream& out, const StudentInfo& c );
friend std::istream& operator>> ( std::istream& in, StudentInfo& c );
};
template<typename... T>
std::ostream& operator<<( std::ostream& out, const StudentInfo<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
out << std::get<idx>( c.members ) << " ";
return out;
}
template<typename... T>
std::istream& operator>>( std::istream& in, StudentInfo<T...>& c ) {
const size_t numArgs = c.numArgs;
for( size_t idx = 0; idx < numArgs; idx++ )
in >> std::get<idx>( c.members );
return in;
}
I'm still getting a linker error. I could make these a part of the class; but I don't want that behavior. I want them to be defined outside of the class. As it currently stands; everything in the class right now is public only for testing, but once this class works as intended; everything in it will be private as this class will be a friend to another class; where the owning class will have access to all of its private information. I don't know how to get around or resolve this linker error problem.
1>main.obj : error LNK2019: unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class StudentInfo<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,int,class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >,class std::vector<int,class std::allocator<int> > > const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$StudentInfo#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std##V12#HV12#V?$vector#HV?$allocator#H#std###2####Z) referenced in function _main
It's a classic.
When you compile main() (say in "main.cpp"), you have
std::cout << studentA << '\n';
where studentA is a StudentInformation<std::string, std::string, int, std::string, std::vector<int>>.
So the compiler prepares an intermediate file that ask for (call) operator<<() for StudentInformation<std::string, std::string, int, std::string, std::vector<int>>.
That operator<<() should be implemented compiling the other cpp-file, say "operators.cpp".
But compiling "operator.cpp", the compiler doesn't know that an operator<<() for StudentInformation<std::string, std::string, int, std::string, std::vector<int>> is needed. So doesn't implement it.
The linker receive the intermediate files produced compiling "main.cpp" and "operators.cpp"; in the first one finds a call to operator<<() for StudentInformation<std::string, std::string, int, std::string, std::vector<int>> but doesn't find the implementation: linker error.
That's the reason because it's better define template classes (and corresponding template friend operators) in the header, not in cpp file.
Bonus error.
This code in operator<<()
for( size_t idx = 0; idx < numArgs; idx++ )
out << std::get<idx>( c.members) << " ";
and this code in operator>>()
for( size_t idx = 0; idx < numArgs; idx++ )
in >> std::get<idx>( c.members);
is obviously wrong because std::get() needs, for the template parameter, a compile time know value and idx, clearly, isn't know at compile time.
Related
The following code doesn't compile.
error: invalid use of non-static data member 'data'
#include <iostream>
#include <unordered_map>
#include <vector>
class Domain {
public:
enum class fieldname { x_, y_ };
std::unordered_map<fieldname, std::vector<double>> data;
// default constructor. Hard coding is only for this test!
Domain() {
data[Domain::fieldname::x_] = std::vector<double>{1, 23, 4};
data[Domain::fieldname::y_] = std::vector<double>{1, 23, 4};
}
// operator overloading
friend std::vector<double> operator+(fieldname one, fieldname two) {
std::vector<double> result = data[one]; // so we get the right size
for (int i = 0; i < result.size(); ++i) {
result[i] = data[one][i] + data[two][i];
}
return result;
}
};
int main() {
Domain d;
std::vector<double> temp = Domain::fieldname::x_ + Domain::fieldname::y_;
for (auto item : temp) std::cout << item << std::endl;
return 0;
}
I think it is evident from the code what I am trying to accomplish. Could someone suggest how the operator + can be overloaded so that the enum classes can be used as a proxy for vectors which are members of a class?
I have a class that is quite similar to an STL-vector (the differences are not important for the pybind11 type caster, so I will ignore them here). I have written a type caster for this class. A minimal working example of my code is given below. An example showing the problem is included below the code.
The problem is that my caster is quite limited (because I have used py::array_t). In principle the interface does accept tuples, lists, and numpy-arrays. However, when I overload based on typename, the interface fails for inputted tuples and lists (simply the first overload is selected even though it is the incorrect type).
My question is: How can I make the type caster more robust? Is there an effective way to re-use as much as possible existing type casters for STL-vector-like classes?
C++ code (including pybind11 interface)
#include <iostream>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
// class definition
// ----------------
template<typename T>
class Vector
{
private:
std::vector<T> mData;
public:
Vector(){};
Vector(size_t N) { mData.resize(N); };
auto data () { return mData.data (); };
auto data () const { return mData.data (); };
auto begin() { return mData.begin(); };
auto begin() const { return mData.begin(); };
auto end () { return mData.end (); };
auto end () const { return mData.end (); };
size_t size () const { return mData.size (); };
std::vector<size_t> shape() const { return std::vector<size_t>(1, mData.size()); }
std::vector<size_t> strides() const { return std::vector<size_t>(1, sizeof(T) ); }
template<typename It> static Vector<T> Copy(It first, It last) {
Vector out(last-first);
std::copy(first, last, out.begin());
return out;
}
};
// C++ functions: overload based on type
// -------------------------------------
Vector<int> foo(const Vector<int> &A){ std::cout << "int" << std::endl; return A; }
Vector<double> foo(const Vector<double> &A){ std::cout << "double" << std::endl; return A; }
// pybind11 type caster
// --------------------
namespace pybind11 {
namespace detail {
template<typename T> struct type_caster<Vector<T>>
{
public:
PYBIND11_TYPE_CASTER(Vector<T>, _("Vector<T>"));
bool load(py::handle src, bool convert)
{
if ( !convert && !py::array_t<T>::check_(src) ) return false;
auto buf = py::array_t<T, py::array::c_style | py::array::forcecast>::ensure(src);
if ( !buf ) return false;
auto rank = buf.ndim();
if ( rank != 1 ) return false;
value = Vector<T>::Copy(buf.data(), buf.data()+buf.size());
return true;
}
static py::handle cast(const Vector<T>& src, py::return_value_policy policy, py::handle parent)
{
py::array a(std::move(src.shape()), std::move(src.strides()), src.data());
return a.release();
}
};
}} // namespace pybind11::detail
// Python interface
// ----------------
PYBIND11_MODULE(example,m)
{
m.doc() = "pybind11 example plugin";
m.def("foo", py::overload_cast<const Vector<int > &>(&foo));
m.def("foo", py::overload_cast<const Vector<double> &>(&foo));
}
Example
import numpy as np
import example
print(example.foo((1,2,3)))
print(example.foo((1.5,2.5,3.5)))
print(example.foo(np.array([1,2,3])))
print(example.foo(np.array([1.5,2.5,3.5])))
Output:
int
[1 2 3]
int
[1 2 3]
int
[1 2 3]
double
[1.5 2.5 3.5]
A very easy solution is to specialise pybind11::detail::list_caster. The type caster now becomes as easy as
namespace pybind11 {
namespace detail {
template <typename Type> struct type_caster<Vector<Type>> : list_caster<Vector<Type>, Type> { };
}} // namespace pybind11::detail
Note that this does require Vector to have the methods:
clear()
push_back(const Type &value)
reserve(size_t n) (seems optional in testing)
Complete example
#include <iostream>
#include <vector>
#include <pybind11/pybind11.h>
#include <pybind11/stl.h>
#include <pybind11/numpy.h>
namespace py = pybind11;
// class definition
// ----------------
template<typename T>
class Vector
{
private:
std::vector<T> mData;
public:
Vector(){};
Vector(size_t N) { mData.resize(N); };
auto data () { return mData.data (); };
auto data () const { return mData.data (); };
auto begin() { return mData.begin(); };
auto begin() const { return mData.begin(); };
auto end () { return mData.end (); };
auto end () const { return mData.end (); };
size_t size () const { return mData.size (); };
void push_back(const T &value) { mData.push_back(value); }
void clear() { mData.clear(); }
void reserve(size_t n) { mData.reserve(n); }
std::vector<size_t> shape() const { return std::vector<size_t>(1, mData.size()); }
std::vector<size_t> strides() const { return std::vector<size_t>(1, sizeof(T) ); }
template<typename It> static Vector<T> Copy(It first, It last) {
printf("Vector<T>::Copy %s\n", __PRETTY_FUNCTION__);
Vector out(last-first);
std::copy(first, last, out.begin());
return out;
}
};
// C++ functions: overload based on type
// -------------------------------------
Vector<int> foo(const Vector<int> &A){ std::cout << "int" << std::endl; return A; }
Vector<double> foo(const Vector<double> &A){ std::cout << "double" << std::endl; return A; }
// pybind11 type caster
// --------------------
namespace pybind11 {
namespace detail {
template <typename Type> struct type_caster<Vector<Type>> : list_caster<Vector<Type>, Type> { };
}} // namespace pybind11::detail
// Python interface
// ----------------
PYBIND11_MODULE(example,m)
{
m.doc() = "pybind11 example plugin";
m.def("foo", py::overload_cast<const Vector<double> &>(&foo));
m.def("foo", py::overload_cast<const Vector<int > &>(&foo));
}
While trying to use a function template that calls a class's specialized static function template it is failing to convert its parameter from the template parameter list.
Here is the function that I'm calling in main:
template<class Engine, typename Type, template<typename = Type> class Distribution, class... DistParams>
Type randomGenerator( RE::SeedType seedType, std::size_t seedValue, std::initializer_list<std::size_t> list, DistParams... params ) {
static Type retVal = 0;
static Engine engine = RE::getEngine<Engine>( seedType, seedValue, list );
static Distribution<Type> dist = RD::getDistribution<Type, Distribution>( params... );
retVal = dist( engine );
return retVal;
}
A little bit about the function above:
The Type represents the return value of the distribution such as int, unsigned, char, etc for Integral Types that work with distributions such as uniform_int_distribution<IntType> or Real Types such as float, double for distributions like uniform_real_distribution<RealType>.
The terms RE & RD are typedefs of two classes.
typedef RandomEngine RE;
typedef RandomDistribution RD;
Both classes follow the same pattern as they have delete constructors and all of their methods are declared a static.
The 2nd line in the function is using the template parameter <class Engine> to represent what kind of engine from the <random> header file we want to use from the static methods in class RandomEngine{...}. Each of the engine types has it's own function to create an engine, seed it by the seeding type and seed values and then returns a reference of the engine. All of the functions in the RandomEngine class are non template functions. So I then went ahead and made generalized function template RE::getEngine<Engine>( parameters ); in this RandomEngine class that you can see in this function template randomGenerator(). Then I specialized this function for each engine type. I had no problems with doing that.
This brings me to the next line with the RandomDistribution class I'm trying to follow a similar pattern as I did with the RandomEngine I made a generalized function template RD::getDistribution<Type, Distribution>( params... );
Before I get to the RD::getDistribution<...>(...) function both of the classes above are non templates. The first class RandomEngine has zero function templates for its engines except the generalized getEngine() The difference with this class as opposed to the RandomDistribution is that every function in this class is a function template, because the <random> library's distribution functions require it. So now I have to not only template this generalized function as I did for getEngine() I have to also use a variadic parameter pack as different distributions takes a different amount of arguments.
Here is my declaration of my generalized function in the RandomDistribution class that is found in the header file:
template<typename Type, template<typename = Type> class Distribution, class... DistParams>
static Distribution<Type>& getDistribution( DistParams... params ) {
return getUniformIntDistribution( params... );
}
Then I have this attempt of a specialization for this function in the cpp file for just one of the other distributions:
template<>
static std::uniform_real_distribution<>& RandomDistribution::getDistribution() {
return RandomDistribution::getUniformRealDistribution();
}
I would like to do this for all the other distributions that I'm supporting.
I am using the stand alone function template randomGenerator() in my main function like this:
{
std::initializer_list<std::size_t> list{};
unsigned val = randomGenerator<std::mt19937, unsigned, std::uniform_int_distribution>
( RE::USE_CHRONO_CLOCK, std::size_t( 12 ), list, 1, 100 );
std::cout << val << std::endl;
}
When I compile RandomGenerator.cpp file it compiles without error;
however, when I compile main.cpp I am getting a compiler error stating that it can not convert from std::uniform_int_distribution<int>& to std::uniform_int_distribution<Type>&
and it is pointing to my class's generalized function template that is declared in RandomGenerator.hfile.
For some reason; Type is not being assigned or casted to the type that is passed into randomGenerator's template parameter list.
I'm stuck at this point. I know what the compiler message is saying; I don't what to do to fix. What can be done to resolve this conversion failure?
Okay scrap that whole idea above: I went and entirely rewritten my classes into a single class. The class itself is now a class template. And it looks like this:
#ifndef GENERATOR_H
#define GENERATOR_H
#include <limits>
#include <chrono>
#include <random>
#include <type_traits>
enum SeedType { USE_CHRONO_CLOCK, USE_RANDOM_DEVICE, USE_SEED_VALUE, USE_SEED_SEQ };
template<class Engine, class Type, template<typename> class Distribution>
class Generator {
public:
using Clock = std::conditional_t<std::chrono::high_resolution_clock::is_steady,
std::chrono::high_resolution_clock,
std::chrono::steady_clock>;
private:
Engine _engine;
Distribution<Type> _distribution;
Type _value;
public:
template<class... Params>
explicit Generator( Engine engine, Params... params ) : _engine( engine ) {
_distribution = Distribution<Type>( params... );
}
void seed( SeedType type = USE_RANDOM_DEVICE, std::size_t seedValue = 0, std::initializer_list<std::size_t> list = {} ) {
switch( type ) {
case USE_CHRONO_CLOCK: { _engine.seed( getTimeNow() ); break; }
case USE_RANDOM_DEVICE: { std::random_device device{};
_engine.seed( device() ); break; }
case USE_SEED_VALUE: { _engine.seed( seedValue ); break; }
case USE_SEED_SEQ: { std::seed_seq seq( list );
_engine.seed( seq ); break; }
}
}
void generate() {
_value = _distribution( _engine );
}
Type getGeneratedValue() const {
return _value;
}
Distribution<Type> getDistribution() const {
return _distribution;
}
std::size_t getTimeNow() {
std::size_t now = static_cast<std::size_t>(Clock::now().time_since_epoch().count());
return now;
}
};
#endif // !GENERATOR_H
And to use it is as simple as:
#include <iostream>
#include <iomanip>
#include <vector>
#include "generator.h"
int main() {
// Engine, Seeding Type, & Distribution Combo 1
std::mt19937 engine1;
Generator<std::mt19937, short, std::uniform_int_distribution> g1( engine1, 1, 100 );
g1.seed( USE_RANDOM_DEVICE );
std::vector<short> vals1;
for( unsigned int i = 0; i < 200; i++ ) {
g1.generate();
auto v = g1.getGeneratedValue();
vals1.push_back( v );
}
int i = 0;
for( auto& v : vals1 ) {
if( (i % 10) != 0 ) {
std::cout << std::setw( 3 ) << v << " ";
} else {
std::cout << '\n' << std::setw( 3 ) << v << " ";
}
i++;
}
std::cout << "\n\n";
// Engine, Seeding Type, & Distribution Combo 2
std::ranlux48 engine2;
std::initializer_list<std::size_t> list2{ 3, 7, 13, 17, 27, 31, 43 };
Generator<std::ranlux48, unsigned, std::binomial_distribution> g2( engine2, 50, 0.75 );
g2.seed( USE_SEED_SEQ, std::size_t(7), list2 );
std::vector<unsigned> vals2;
for( int i = 0; i < 200; i++ ) {
g2.generate();
auto v = g2.getGeneratedValue();
vals2.push_back( v );
}
for( auto& v : vals2 ) {
if( (i % 10) != 0 ) {
std::cout << std::setw( 3 ) << v << " ";
} else {
std::cout << '\n' << std::setw( 3 ) << v << " ";
}
i++;
}
std::cout << "\n\n";
// Engine, Seeding Type, & Distribution Combo 3
std::minstd_rand engine3;
Generator<std::minstd_rand, float, std::gamma_distribution> g3( engine3, 0.22222f, 0.7959753f );
g3.seed( USE_CHRONO_CLOCK );
std::vector<float> vals3;
for( int i = 0; i < 200; i++ ) {
g3.generate();
auto v = g3.getGeneratedValue();
vals3.push_back( v );
}
for( auto& v : vals3 ) {
if( (i % 5 ) != 0 ) {
std::cout << std::setw( 12 ) << v << " ";
} else {
std::cout << '\n' << std::setw( 12 ) << v << " ";
}
i++;
}
std::cout << "\n\n";
std::cout << "\nPress any key and enter to quit.\n";
std::cin.get();
return 0;
}
I have a class "PclProc" and I want to use std::sort.
I write a compare function in the same class because this comparing need the "in_ptr" which is a variable in the same class.
But as I did as following, there is always an error:
error: no matching function for call to
‘sort(std::vector::iterator, std::vector::iterator,
)’
std::sort(cloud_indice.indices.begin(),cloud_indice.indices.end(),PclProc::MyCompare);
bool PclProc::MyCompare(int id1, int id2)
{
return in_ptr->points[id1].z<in_ptr->points[id2].z;
}
float PclProc::MedianZDist(pcl::PointIndices cloud_indice)
{
std::sort(cloud_indice.indices.begin(),cloud_indice.indices.end(),PclProc::MyCompare);
int size=cloud_indice.indices.size();
float median_x,median_y;
...
Example of a functor being used for std::sort. vector D is the data, vector I is the indices to D. I is sorted according to D with std::sort using the functor. std::sort only creates one instance of class lessthan, then uses that one instance for all of the compares.
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <iomanip>
#include <vector>
typedef unsigned int uint32_t;
#define SIZE 16
class example{
public:
std::vector<uint32_t> D; // data
std::vector<uint32_t> I; // indices
example(void)
{
D.resize(SIZE);
I.resize(SIZE);
for(uint32_t i = 0; i < SIZE; i++){
D[i] = rand()%100;
I[i] = i;
}
}
void displaydata(void)
{
for(size_t i = 0; i < SIZE; i++)
std::cout << std::setw(3) << D[I[i]];
std::cout << std::endl;
}
class lessthan // lessthan functor for std::sort
{
public:
const example &x;
lessthan(const example &e ) : x(e) { }
bool operator()(const uint32_t & i0, const uint32_t & i1)
{
return x.D[i0] < x.D[i1];
}
};
void sortindices(void)
{
std::sort(I.begin(), I.end(), lessthan(*this));
}
};
int main()
{
example x;
x.displaydata();
x.sortindices();
x.displaydata();
return 0;
}
A smart pointer clears the memory if the pointer gets out of scope. I wanted to adapt this to a file descriptor, like a socket. There you need a user defined deleter, because close() is the function to free the file descriptor (fd) resources.
I found this useful page, unfortunately, most approaches did not work for me. Below is a working solution I found up to now, which is a little nasty. Because uniqu_ptr expects a pointer I created int *fd to store the fd value, therefore, I had to close(*fd) and delete fd in my custom deleter.
(1) Is there a better way?
Options A and B, which are based on the hints provided by the mentioned web page, are much nicer but causing odd compiler errors.
(2) Does anyone know how to correctly use these alternatives?
I'm using Qt Creator 3.0.1 with CONFIG += c++11 option and gcc version 4.8.2
#include "ccommhandler.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <memory>
#include <qdebug.h>
//for Option A and B
struct CloseHandleDeleter {
typedef int pointer;
void operator()(int handle) const
{
}
};
//custom deleter, working
class MyComplexDeleter
{
public:
MyComplexDeleter() {}
void operator()(int* ptr) const
{
qDebug() << "Deleting ";
close(*ptr);
delete ptr;
}
};
CCommHandler::CCommHandler()
{
//Option A doesn't work
//std::unique_ptr<int, CloseHandleDeleter> file( socket(AF_INET, SOCK_STREAM, 0) );
//Option B doesn't work
//std::unique_ptr<int, int()(int)> filePtr( socket(AF_INET, SOCK_STREAM, 0) , close);
MyComplexDeleter deleter;
int *fd = new int;
*fd = socket(AF_INET, SOCK_STREAM, 0);
std::unique_ptr<int, MyComplexDeleter> p( fd , deleter);
}
Edit:
The posted answer by Nevin is right, it solves my initial problem.
The comment of learnvst caused to rethink my problem, and I have to say I may made it much more complex than needed, because the following simple class should also solve my problem of auto-free the memory of a resource or as in my case, to close the file descriptor:
class SocketHandler
{
int _fd;
public:
SocketHandler(int FD):_fd(FD){}
~SocketHandler() { if(_fd!=-1) close(_fd); }
operator int() const { return _fd; }
};
Because fd isn't a pointer, I wouldn't try to pigeonhole it into unique_ptr. Instead, create a custom class whose interface is based on unique_ptr, as in (caution: totally untested):
class unique_fd
{
public:
constexpr unique_fd() noexcept = default;
explicit unique_fd(int fd) noexcept : fd_(fd) {}
unique_fd(unique_fd&& u) noexcept : fd_(u.fd_) { u.fd_ = -1; }
~unique_fd() { if (-1 != fd_) ::close(fd_); }
unique_fd& operator=(unique_fd&& u) noexcept { reset(u.release()); return *this; }
int get() const noexcept { return fd_; }
operator int() const noexcept { return fd_; }
int release() noexcept { int fd = fd_; fd_ = -1; return fd; }
void reset(int fd = -1) noexcept { unique_fd(fd).swap(*this); }
void swap(unique_fd& u) noexcept { std::swap(fd_, u.fd_); }
unique_fd(const unique_fd&) = delete;
unique_fd& operator=(const unique_fd&) = delete;
// in the global namespace to override ::close(int)
friend int close(unique_fd& u) noexcept { int closed = ::close(u.fd_); u.fd_ = -1; return closed; }
private:
int fd_ = -1;
};