Is it possible to specialize a function (or a class at least) to select between constant (compile-time!) integer and all other arguments? And if so, it would be nice to specialize (enable_if) for specific constant values only.
In the example below this would mean output "var", "const", and "var", not three "var"s.
#include <type_traits>
#include <iostream>
using namespace std;
struct test
{
template <typename T>
test& operator=(const T& var) { cout << "var" << endl; return *this; }
template <int n> // enable_if< n == 0 >
test& operator=(int x) { cout << "const" << endl; return *this; }
};
int main()
{
test x;
x = "x";
x = 1;
int y = 55;
x = y;
return 0;
}
UPDATE: edited the code to emphasize that it has to be compile-time constant.
To get var, const, var in your example you can do that.
struct test {
template <typename T>
test& operator=(const T& var) { cout << "var" << endl; return *this; }
test& operator=(int &&x) { cout << "const" << endl; return *this; }
};
It will work for all temporaries, but it will fail for:
const int yy = 55;
x = yy;
To make it work for such a case too you will need to add:
test& operator=(int &x) { cout << "var" << endl; return *this; }
test& operator=(const int &x) { cout << "const" << endl; return *this; }
Related
I'm trying to create 2 std::unordered_map, one holds <A, int> and the second one holds <int&, A&>.
I'll explain at the end why I want to do this if you're curious.
My problem is that k_i has value of type std::reference_wrapper, k_i.insert doesn't work. But if I make k_i to have value std::reference_wrapper<const A>, the insert works.
I just can't figure out why is this and I am curious.
<<<<<Edit:
The thing is that find returns std::pair<const Ket, T> as stated by
Eljay in the comments. Because of this, the second std::unordered_map needs to have the value const.
<<<<<
Code:
Compiler: g++ version 10.1
Compile flags: -Wall -Wextra -std=c++20
#include <unordered_map>
#include <iostream>
#include <string>
#include <functional>
class A {
public:
A(const int x) : x(x) {
std::cout << "A::A(const int x) : x(" << x << ")\n";
}
A(const A& a) {
std::cout << "A::A {" << x << "} (const A& a {" << a.x << "} )\n";
x = a.x;
}
A(A&& a) {
std::cout << "A::A {" << x << "} (A&& a {" << a.x << "} )\n";
x = a.x;
}
A& operator=(const A& a) {
std::cout << "A::operator= {" << x << "} (const A& a)\n";
x = a.x;
return *this;
}
A& operator=(A&& a) {
std::cout << "A::operator= {" << x << "} (A&& a)\n";
x = a.x;
return *this;
}
~A() {
std::cout << "A::~A(" << x << ")\n";
}
friend std::ostream& operator<<(std::ostream& os, const A& dt);
int x;
};
std::ostream& operator<<(std::ostream& os, const A& dt) {
return os << dt.x;
}
template <typename K, typename V, typename... args>
void print_um(const std::unordered_map<K, V, args...> &umap) {
for (const auto &[x, y] : umap) {
std::cout << "(" << x << "," << std::ref(y).get() << "); ";
}
std::cout << "\n";
}
template <typename T>
struct MyHash {
std::size_t operator()(T const& s) const noexcept {
return std::hash<int>{}(std::ref(s).get());
}
};
template <typename T>
struct MyEquals {
constexpr bool operator()(const T &lhs, const T &rhs) const {
return lhs == rhs;
}
};
struct MyHash_A {
std::size_t operator()(A const& s) const noexcept {
return std::hash<int>{}(s.x);
}
};
struct MyEquals_A {
constexpr bool operator()(const A &lhs, const A &rhs) const {
return lhs.x == rhs.x;
}
};
int main() {
std::unordered_map<A, int, MyHash_A, MyEquals_A> k_s;
std::unordered_map<std::reference_wrapper<int>, std::reference_wrapper<const A>, MyHash<std::reference_wrapper<int>>, MyEquals<std::reference_wrapper<int>>> k_i;
{
A a(5);
std::cout << "1----\n";
k_s[a] = 12;
std::cout << "2----\n";
}
std::cout << "3----\n";
print_um<>(k_s);
std::cout << "4----\n";
A a(5);
std::cout << "5----\n";
auto it = k_s.find(a);
std::cout << "6----\n";
k_i.emplace((*it).second, (*it).first);
// // k_i[(*it).second] = ref_name;
std::cout << "7----\n";
print_um<>(k_s);
std::cout << "8----\n";
print_um<>(k_i);
std::cout << "9----\n";
int x = 12;
int &ref = x;
auto is_there = k_i.find(ref);
if (is_there != k_i.end()) {
std::cout << "elem: " << (*is_there).second.get() << "\n";
} else {
std::cout << "why? :(\n";
}
std::cout << "10---\n";
return 0;
}
As to why I create this code, I was thinking to be able to access some data by value or by key interchangeably (is there some better data structure? ). Like an username and a token, sometimes I have one, other times I have the other and using references I ensure that I don't waste space. Ofc, if one value has to change, I would invalidate the bucket position in the unordered_map because of the key, but I would treat that problem at a later date. Another motive is to learn some more C++ and test its limits (or mine).
From UnorderedAssociativeContainer requirements:
For std::unordered_map and std::unordered_multimap the value type is std::pair<const Key, T>.
In your code k_s is unordered_map<A, int>, so the value type is pair<const A, int>. In here:
auto it = k_s.find(a);
you get a "pointer" to such pair, and type of (*it).first is const A.
Your k_i is unordered_map<..., ref<A>> and when you do insert here:
k_i.emplace(..., (*it).first);
you essentially attempt to initialize ref<A> with const A, which obviously cannot work.
When you change k_i type to unordered_map<..., ref<const A>>, then you initialize ref<const A> with const A, which is fine.
Many have mentioned in the comment that Key type must be const. However the OP seems to wonder why the value type in k_i also need to be a const.
The reason for that is because you are referencing the key from k_s, which would be const A, and you can not reference it with a non-const reference.
To properly declare k_s, you might want to do something like:
std::unordered_map<
std::reference_wrapper<decltype(k_s)::value_type::second_type>,
std::reference_wrapper<decltype(k_s)::value_type::first_type>,
yourHash, yourComp
> k_s;
One alternative solution for you is to use another container that actually supports bidirectional lookup, such as Boost.Bimap.
I'm trying to write a single function template instead of a bunch of similar overloads for the insertion operator. The redundant overloaded versions work, but when I try to unite them in a single function template, the compiler complains of ambiguity. For example:
#include <iostream>
#include <list>
class fooBar
{
public:
fooBar(int iVal): iValue(iVal) {}
int getValue() {return iValue;}
private:
int iValue;
};
class foo
{
public:
foo()
{
for(int i = 0; i < 64; i++)
lstFooBars.push_back(fooBar(i));
}
std::list<fooBar>& getList()
{
return lstFooBars;
}
private:
std::list<fooBar> lstFooBars;
};
class bar
{
public:
bar()
{
for(int i = 0; i < 64; i++)
lstFooBars.push_back(fooBar(i));
}
std::list<fooBar>& getList()
{
return lstFooBars;
}
private:
std::list<fooBar> lstFooBars;
};
std::ostream& operator<<(std::ostream& osOut, fooBar& fbrFooBar)
{
osOut << fbrFooBar.getValue();
return osOut;
}
template <typename T> std::ostream& operator<<(std::ostream& osOut, T& tContainer)
{
for(fooBar fbrFooBar: tContainer.getList())
osOut << "[" << fbrFooBar << "] ";
return osOut;
}
int main()
{
foo fooFoo;
bar barBar;
std::cout << std::endl << fooFoo << std::endl << std::endl;
std::cout << std::endl << barBar << std::endl << std::endl;
return 0;
}
...and the compiler tells me that:
test.cpp: In function ‘std::ostream& operator<<(std::ostream&, T&)’:
test.cpp:63:9: error: ambiguous overload for ‘operator<<’ (operand types are ‘std::ostream’ {aka ‘std::basic_ostream<char>’} and ‘const char [2]’)
63 | osOut << "[" << fbrFooBar << "] ";
| ~~~~~ ^~ ~~~
| | |
| | const char [2]
| std::ostream {aka std::basic_ostream<char>}
Why does it work when you overload the same function over and over for each case and it doesn't compile like this? What am I missing here?
You've inadvertedly added a possible overload for const char* by making this:
template<typename T>
std::ostream& operator<<(std::ostream& osOut, T& tContainer)
If you narrow it down a bit with SFINAE, it should work.
This overload will only work for types with a getList() member function for example:
template<typename T, typename U = decltype(std::declval<T>().getList())>
std::ostream& operator<<(std::ostream& osOut, T& tContainer)
operator<< by default takes chars as argument, not string literals (inside "s) https://www.cplusplus.com/reference/ostream/ostream/operator-free/.
So, in order to make the call in the code you provide not ambiguous, you should try either to use single chars, or std::string:
#include <iostream>
#include <list>
#include <string>
class fooBar
{
public:
fooBar(int iVal): iValue(iVal) {}
int getValue() {return iValue;}
private:
int iValue;
};
class foo
{
public:
foo()
{
for(int i = 0; i < 64; i++)
lstFooBars.push_back(fooBar(i));
}
std::list<fooBar>& getList()
{
return lstFooBars;
}
private:
std::list<fooBar> lstFooBars;
};
class bar
{
public:
bar()
{
for(int i = 0; i < 64; i++)
lstFooBars.push_back(fooBar(i));
}
std::list<fooBar>& getList()
{
return lstFooBars;
}
private:
std::list<fooBar> lstFooBars;
};
std::ostream& operator<<(std::ostream& osOut, fooBar& fbrFooBar)
{
osOut << fbrFooBar.getValue();
return osOut;
}
template <typename T> std::ostream& operator<<(std::ostream& osOut, T& tContainer)
{
for(fooBar fbrFooBar: tContainer.getList())
//osOut << std::string("[") << fbrFooBar << std::string("] "); // solution 1: use std::string
osOut << '[' << fbrFooBar << ']' << ' '; // solution 2: use single chars
return osOut;
}
int main()
{
foo fooFoo;
bar barBar;
std::cout << std::endl << fooFoo << std::endl << std::endl;
std::cout << std::endl << barBar << std::endl << std::endl;
return 0;
}
As far as I know, this seems to be impossible in a straightforward way. Making the member const makes it const for everyone. I would like to have a read-only property, but would like to avoid the typical "getter". I'd like const public, mutable private. Is this at all possible in C++?
Currently all I can think of is some trickery with templates and friend. I'm investigating this now.
Might seem like a stupid question, but I have been surprised by answers here before.
A possible solution can be based on an inner class of which the outer one is a friend, like the following one:
struct S {
template<typename T>
class Prop {
friend struct S;
T t;
void operator=(T val) { t = val; }
public:
operator const T &() const { return t; }
};
void f() {
prop = 42;
}
Prop<int> prop;
};
int main() {
S s;
int i = s.prop;
//s.prop = 0;
s.f();
return i, 0;
}
As shown in the example, the class S can modify the property from within its member functions (see S::f). On the other side, the property cannot be modified in any other way but still read by means of the given operator that returns a const reference to the actual variable.
There seems to be another, more obvious solution: use a public const reference member, pointing to the private, mutable, member. live code here.
#include <iostream>
struct S {
private:
int member;
public:
const int& prop;
S() : member{42}, prop{member} {}
S(const S& s) : member{s.member}, prop{member} {}
S(S&& s) : member(s.member), prop{member} {}
S& operator=(const S& s) { member = s.member; return *this; }
S& operator=(S&& s) { member = s.member; return *this; }
void f() { member = 32; }
};
int main() {
using namespace std;
S s;
int i = s.prop;
cout << i << endl;
cout << s.prop << endl;
S s2{s};
// s.prop = 32; // ERROR: does not compile
s.f();
cout << s.prop << endl;
cout << s2.prop << endl;
s2.f();
S s3 = move(s2);
cout << s3.prop << endl;
S s4;
cout << s4.prop << endl;
s4 = s3;
cout << s4.prop << endl;
s4 = S{};
cout << s4.prop << endl;
}
I like #skypjack's answer, but would have written it somehow like this:
#include <iostream>
template <class Parent, class Value> class ROMember {
friend Parent;
Value v_;
inline ROMember(Value const &v) : v_{v} {}
inline ROMember(Value &&v) : v_{std::move(v)} {}
inline Value &operator=(Value const &v) {
v_ = v;
return v_;
}
inline Value &operator=(Value &&v) {
v_ = std::move(v);
return v_;
}
inline operator Value& () & {
return v_;
}
inline operator Value const & () const & {
return v_;
}
inline operator Value&& () && {
return std::move(v_);
}
public:
inline Value const &operator()() const { return v_; }
};
class S {
template <class T> using member_t = ROMember<S, T>;
public:
member_t<int> val = 0;
void f() { val = 1; }
};
int main() {
S s;
std::cout << s.val() << "\n";
s.f();
std::cout << s.val() << "\n";
return 0;
}
Some enable_ifs are missing to really be generic to the core, but the spirit is to make it re-usable and to keep the calls looking like getters.
This is indeed a trickery with friend.
You can use curiously recurring template pattern and friend the super class from within a property class like so:
#include <utility>
#include <cassert>
template<typename Super, typename T>
class property {
friend Super;
protected:
T& operator=(const T& val)
{ value = val; return value; }
T& operator=(T&& val)
{ value = val; return value; }
operator T && () &&
{ return std::move(value); }
public:
operator T const& () const&
{ return value; }
private:
T value;
};
struct wrap {
wrap() {
// Assign OK
prop1 = 5; // This is legal since we are friends
prop2 = 10;
prop3 = 15;
// Move OK
prop2 = std::move(prop1);
assert(prop1 == 5 && prop2 == 5);
// Swap OK
std::swap(prop2, prop3);
assert(prop2 == 15 && prop3 == 5);
}
property<wrap, int> prop1;
property<wrap, int> prop2;
property<wrap, int> prop3;
};
int foo() {
wrap w{};
w.prop1 = 5; // This is illegal since operator= is protected
return w.prop1; // But this is perfectly legal
}
Using a std::shared_ptr expresses shared ownership and optionality (with its possibility to be null).
I find myself in situations where I want to express shared ownership only in my code, and no optionality. When using a shared_ptr as a function parameter I have to let the function check that it is not null to be consistent/safe.
Passing a reference instead of course is an option in many cases, but I sometimes would also like to transfer the ownership, as it is possible with a shared_ptr.
Is there a class to replace shared_ptr without the possibility to be null, some convention to handle this problem, or does my question not make much sense?
You are asking for not_null wrapper class. Fortunately your issue is already addressed by C++ experts guideline and there are already example implementations - like this one. Search for not_null class template.
You could write a wrapper around std::shared_ptr that only allows creation from non-null:
#include <memory>
#include <cassert>
template <typename T>
class shared_reference
{
std::shared_ptr<T> m_ptr;
shared_reference(T* value) :m_ptr(value) { assert(value != nullptr); }
public:
shared_reference(const shared_reference&) = default;
shared_reference(shared_reference&&) = default;
~shared_reference() = default;
T* operator->() { return m_ptr.get(); }
const T* operator->() const { return m_ptr.get(); }
T& operator*() { return *m_ptr.get(); }
const T& operator*() const { return *m_ptr.get(); }
template <typename XT, typename...XTypes>
friend shared_reference<XT> make_shared_reference(XTypes&&...args);
};
template <typename T, typename...Types>
shared_reference<T> make_shared_reference(Types&&...args)
{
return shared_reference<T>(new T(std::forward<Types>(args)...));
}
Please note that operator= is missing yet. You should definitely add it.
You can use it like this:
#include <iostream>
using std::cout;
using std::endl;
struct test
{
int m_x;
test(int x) :m_x(x) { cout << "test("<<m_x<<")" << endl; }
test(const test& t) :m_x(t.m_x) { cout << "test(const test& " << m_x << ")" << endl; }
test(test&& t) :m_x(std::move(t.m_x)) { cout << "test(test&& " << m_x << ")" << endl; }
test& operator=(int x) { m_x = x; cout << "test::operator=(" << m_x << ")" << endl; return *this;}
test& operator=(const test& t) { m_x = t.m_x; cout << "test::operator=(const test& " << m_x << ")" << endl; return *this;}
test& operator=(test&& t) { m_x = std::move(t.m_x); cout << "test::operator=(test&& " << m_x << ")" << endl; return *this;}
~test() { cout << "~test(" << m_x << ")" << endl; }
};
#include <string>
int main() {
{
auto ref = make_shared_reference<test>(1);
auto ref2 = ref;
*ref2 = test(5);
}
{
test o(2);
auto ref = make_shared_reference<test>(std::move(o));
}
//Invalid case
//{
// test& a = *(test*)nullptr;
// auto ref = make_shared_reference<test>(a);
//}
}
Output:
test(1)
test(5)
test::operator=(test&& 5)
~test(5)
~test(5)
test(2)
test(test&& 2)
~test(2)
~test(2)
Example on Coliru
I hope I didn't forget anything that might result in undefined behaviour.
After taking a look at GSL's not_null class, which calls std::terminate() instead of abort();
Here is how I achieved it:
template <typename T>
class NonNull : public std::shared_ptr<T> {
typedef std::shared_ptr<T> super;
public:
inline NonNull()
: super(new T())
{
if ( ! super::get()) {
abort(); // Out of memory.
}
}
inline explicit NonNull(T *ptr)
: super(ptr)
{
if ( ! super::get()) {
abort(); // Input was null.
}
}
}
Basically, forces us to construct the class of T type.
Usage:
// Directly is a `std::shared_ptr` type:
NonNull<MyClass> myVariable;
// Unlike:
gsl::not_null<std::shared_ptr<MyClass > > myVariable;
I'd like to wrap std::cout for formatting, like so:
mycout([what type?] x, [optional args]) {
... // do some formatting on x first
std::cout << x;
}
and still be able to use expressive syntax like
mycout("test" << i << endl << somevar, indent)
instead of being forced to be more verbose like
mycout(std::stringstream("test") << i ...)
How can I implement this? What type to make x?
Edit: added consideration for optional arguments
How about this:
struct MyCout {};
extern MyCout myCout;
template <typename T>
MyCout& operator<< (MyCout &s, const T &x) {
//format x as you please
std::cout << x;
return s;
}
And put MyCout myCout; into any one .cpp file.
You can then use myCout like this:
myCout << "test" << x << std::endl;
And it will call the template operator<< which can do the formatting.
Of course, you can also provide overloads of the operator for special formatting of specific types if you want to.
EDIT
Apparently (thanks to #soon), for standard manipulators to work, a few more overloads are necessary:
MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ostream &)) {
f(std::cout);
return s;
}
MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ios &)) {
f(std::cout);
return s;
}
MyCout& operator<< (MyCout &s, std::ostream& (*f)(std::ios_base &)) {
f(std::cout);
return s;
}
EDIT 2
I may have misunderstoor your original requirements slightly. How about this (plus the same manipulator overloads as above):
struct MyCout
{
std::stringstream s;
template <typename T>
MyCout& operator << (const T &x) {
s << x;
return *this;
}
~MyCout() {
somehow_format(s);
std::cout << s.str();
}
};
int main() {
double y = 1.5;
MyCout() << "test" << y;
}
This comes easy with variadic template arguments:
template <class T>
void print(T t)
{
std::cout << t;
}
template <class T, class... Args>
void print(T t, Args... args)
{
std::cout << t << std::endl;
print(args...);
}
int main()
{
std::cout << std::boolalpha;
print(3, 's', true, false);
}
Output:
3
s
true
false
Live Demo
A variation from the answers:
#include <iostream>
using namespace std;
class MyCout
{
public:
MyCout& operator()(bool indent) {
if ( indent ) cout << '\t';
return *this;
}
template<class T>
MyCout& operator<<(T t) {
cout << t;
return *this;
}
MyCout& operator<<(ostream& (*f)(ostream& o)) {
cout << f;
return *this;
};
};
int main()
{
MyCout mycout;
int x = 10;
mycout(true)<< "test" << 2 << x << endl ;
}
You can use this kind of class:
#include <iostream>
using namespace std;
class CustomOut
{
public:
template<class T>
CustomOut& operator<<(const T& obj)
{
cout << " my-cout " << obj;
return *this;
}
};
int main()
{
CustomOut mycout;
mycout << "test" << 4 << "\n" << 3.4;
}
You'd need more code to use std::endl and other functors, so i've used here simple \n instead.