Item 25 in Effective c++ third edition, Scott Meyers suggests to implement swap in the same namespace as the class, and then when swapping to employ the using std::swap, and there the author says :
For example, if you were to write the call to swap this way:
std::swap(obj1,obj2); // the wrong way to call swap
you'd force the compiler to consider only the swap in std, thus
eliminating the possibility of getting a more appropriate T-specific
version defined elsewhere. Alas, some misguided programmers do qualify
calls to swap in this way, and that is why it's important to totally
specialize std::swap for your classes.
The author recommends to always swap objects this way :
#include <iostream>
#include <utility>
#define CUSTOM_SWAP
namespace aaa{
struct A
{
};
#ifdef CUSTOM_SWAP
void swap( A&, A& )
{
std::cout<<"not std::swap"<<std::endl;
}
#endif
}
int main()
{
using std::swap; // add std::swap to a list of possible resolutions
aaa::A a1;
aaa::A a2;
swap(a1,a2);
}
Why isn't std::swap in global namespace? That way, it would be simpler to add custom swap functions.
Probably because the standard says so, 17.6.1.1/2:
All library entities except macros, operator new and operator delete are defined within the namespace std or namespaces nested within namespace std.
And you would still need to put using ::swap sometimes, so it would introduce even more special cases. Here I use func instead of swap - http://ideone.com/WAWBfZ :
#include <iostream>
using namespace std;
template <class T>
auto func(T) -> void
{
cout << "::f" << endl;
}
namespace my_ns {
struct my_struct {};
auto func(my_struct) -> void
{
cout << "my_ns::func" << endl;
}
auto another_func() -> void
{
// won't compile without `using ::func;`
func(123);
}
}
auto main() -> int {}
fails with
prog.cpp: In function ‘void my_ns::another_func()’:
prog.cpp:21:17: error: could not convert ‘123’ from ‘int’ to ‘my_ns::my_struct’
func(123);
Related
Let's say I am writing some generic algorithm in lib namespace that calls a customisation point my_func.
First attempt is using ADL for my_func
one of the user wants to specialise my_func for his type, which is an alias to std type. Surely define it in his namespace won't work because ADL won't work for alias. Defining it in std namespace is not allowed by the standard. the only option left seems to define in the algorithm's namespace lib. But this doesn't work either if the end user includes the algorithm header before including the customisation header.
#include <iostream>
#include <array>
// my_algorithm.hpp
namespace lib{
template<typename T>
void my_algorithm(const T& t){
my_func(t);
}
} // namespace lib
// user1.hpp
namespace user1{
struct Foo1{
// this is working as expected (ADL)
friend void my_func(const Foo1&){
std::cout << "called user1's customisation\n";
}
};
} // namespace user1
// user2.hpp
namespace user2{
using Foo2 = std::array<int,1>;
// this won't work because Foo2 is actually in std namespace
void my_func(const Foo2&){
std::cout << "called user2's customisation\n";
}
} // namespace user2
/* surely this isn't allowed
namespace std{
void my_func(const user2::Foo2&){
std::cout << "called user2's customisation\n";
}
} //namespace std
*/
// another attempt to costomize in the algorithm's namespace
// this won't work because my_func isn't seen before my_algorithm
namespace lib{
void my_func(const user2::Foo2&){
std::cout << "called user2's customisation\n";
}
}
// main.cpp
// #include "algorithm.hpp"
// #include "user1.hpp"
// #include "user2.hpp"
int main(){
lib::my_algorithm(user1::Foo1{});
lib::my_algorithm(user2::Foo2{});
}
https://godbolt.org/z/bfdP8s
Second attempt is using niebloids for my_func, which has the same problem as ADL.
Third attempt is using tag_invoke, which should have same problem as ADL, i.e.,
customising in user namespace won't work because my type is an alias to std type
customising in std isn't allowed
customising in lib namespace depends on the order the header includes
The first points seem to be true, but the last point isn't. This seems to work
#include <iostream>
#include <array>
// tag_invoke.hpp overly simplified version
namespace lib_ti{
inline namespace tag_invoke_impl{
inline constexpr struct tag_invoke_fn{
template<typename CP, typename... Args>
decltype(auto) operator()(CP cp, Args&&... args) const{
return tag_invoke(cp, static_cast<Args&&>(args)...);
}
} tag_invoke{};
} // namespace tag_invoke_impl
} // namespace lib_to
// my_algorithm.hpp
// #include "tag_invoke.hpp"
namespace lib{
inline constexpr struct my_func_fn {
template <typename T>
void operator()(const T& t) const{
lib_ti::tag_invoke(*this, t);
}
} my_func{};
template<typename T>
void my_algorithm(const T& t){
my_func(t);
}
} // namespace lib
// user1.hpp
namespace user1{
struct Foo1{
// this is working as expected (ADL)
friend void tag_invoke(lib::my_func_fn, const Foo1&){
std::cout << "called user1's customisation\n";
}
};
} // namespace user1
// user2.hpp
namespace user2{
using Foo2 = std::array<int,1>;
// this won't work because Foo2 is actually in std namespace
void tag_invoke(lib::my_func_fn, const Foo2&){
std::cout << "called user2's customisation\n";
}
} // namespace user2
/* surely this isn't allowed
namespace std{
void tag_invoke(lib::my_func_fn, const user2::Foo2&){
std::cout << "called user2's customisation\n";
}
} //namespace std
*/
// another attempt to customise in the algorithm's namespace
// In ADL case, this does not work. But in this case, it seems to work. why?
namespace lib{
void tag_invoke(lib::my_func_fn, const user2::Foo2&){
std::cout << "called user2's customisation\n";
}
}
// main.cpp
int main(){
lib::my_algorithm(user1::Foo1{});
lib::my_algorithm(user2::Foo2{});
}
https://godbolt.org/z/hsKbKE
Why does this not have the same problem as the First one (raw ADL)?
Forth attempt is using template specialisation, which seems to work normally as expected
#include <iostream>
#include <array>
// my_algorithm.hpp
namespace lib{
template<typename T, typename = void>
struct my_func_impl{
//void static apply(const T&) = delete;
};
inline constexpr struct my_func_fn {
template <typename T>
void operator()(const T& t) const{
using impl = my_func_impl<std::decay_t<T>>;
impl::apply(t);
}
} my_func{};
template<typename T>
void my_algorithm(const T& t){
my_func(t);
}
} // namespace lib
// user1.hpp
namespace user1{
struct Foo1{};
} // namespace user1
namespace lib{
template<>
struct my_func_impl<user1::Foo1>{
void static apply(const user1::Foo1&){
std::cout << "called user1's customisation\n";
}
};
} //namespace lib
// user2.hpp
namespace user2{
using Foo2 = std::array<int,1>;
} // namespace user2
namespace lib{
template<>
struct my_func_impl<user2::Foo2>{
void static apply(const user2::Foo2&){
std::cout << "called user2's customisation\n";
}
};
}
// main.cpp
int main(){
lib::my_algorithm(user1::Foo1{});
lib::my_algorithm(user2::Foo2{});
}
https://godbolt.org/z/r71x6c
What is the best way to write generic algorithms and customisation points and allow clients to customise for aliases for std types?
one of the user wants to specialise my_func for his type, which is an alias to std type
This is the original sin, which is causing you all the pain. Type aliases in C++ are just aliases; they're not new types. You have a generic algorithm that uses a customization point, something like
// stringify_pair is my generic algorithm; operator<< is my customization point
template<class T>
std::string stringify_pair(K key, V value) {
std::ostringstream oss;
oss << key << ':' << value;
return std::move(oss).str();
}
Your user wants to call this generic algorithm with a standard type, like
std::string mykey = "abc";
std::optional<int> myvalue = 42;
std::cout << stringify_pair(mykey, myvalue);
This doesn't work because std::optional<int> doesn't provide an operator<<.
It can't possibly be made to work, because your user doesn't own the std::optional<int> type and therefore can't add operations to it. (They can certainly try, physically speaking; but it doesn't work from a philosophical point of view, which is why you keep running into roadblocks every time you get (physically) close.)
The simplest way for the user to make their code work is for them to "take legal ownership" of the type definition, instead of relying on somebody else's type.
struct OptionalInt {
std::optional<int> data_;
OptionalInt(int x) : data_(x) {}
friend std::ostream& operator<<(std::ostream&, const OptionalInt&);
};
OptionalInt myvalue = 42; // no problem now
You ask why tag_invoke doesn't have the same problem as raw ADL. I believe the answer is that when you call lib::my_func(t), which calls lib_ti::tag_invoke(*this, t), which does an ADL call to tag_invoke(lib::my_func, t), it's doing ADL with an argument list that includes both your t (which doesn't really matter) and that first argument of type lib::my_func_fn (which means lib is an associated namespace for this call). That's why it finds the tag_invoke overload you put into namespace lib.
In the raw ADL case, namespace lib is not an associated namespace of the call to my_func(t). The my_func overload you put into namespace lib is not found, because it isn't found by ADL (not in an associated namespace) and it isn't found by regular unqualified lookup either (because waves hands vaguely two-phase lookup).
What is the best way to write generic algorithms and customisation points and allow clients to customise for aliases for std types?
Don't. The "interface" of a type — what operations it supports, what you're allowed to do with it — is under the control of the author of the type. If you're not the author of the type, don't add operations to it; instead, create your own type (possibly by inheritance, preferably by composition) and give it whatever operations you want.
In the worst case, you end up with two different users in different parts of the program, one doing
using IntSet = std::set<int>;
template<> struct std::hash<IntSet> {
size_t operator()(const IntSet& s) const { return s.size(); }
};
and the other one doing
using IntSet = std::set<int>;
template<> struct std::hash<IntSet> {
size_t operator()(const IntSet& s, size_t h = 0) const {
for (int i : s) h += std::hash<int>()(i);
return h;
}
};
and then both of them try to use std::unordered_set<IntSet>, and then boom, ODR violation and undefined behavior at runtime when you pass a std::unordered_set<IntSet> from one object file to another and they agree on the name of std::hash<std::set<int>> but disagree on its meaning. It's just a huge can of worms. Don't open it.
I was trying to provide a custom operator< for a class from an external library. This class is within that library's namespace, however, the operator I wanted to define is not. Now if I define a std::variant and want to use it in a std::set, the compilation fails as it can't detect the operator<. Here's an example (godbolt):
#include <variant>
#include <set>
#include <string>
namespace myClasses
{
struct classA
{
classA(const unsigned int i) :i(i) {};
int i;
};
struct classB
{
classB(const unsigned int u) :u(u) {};
unsigned int u;
};
}// namespace myClasses
//namespace myClasses { //<- uncomment this
bool operator<(const myClasses::classA &v, const myClasses::classA &w)
{
return v.i < w.i;
}
bool operator<(const myClasses::classB &v, const myClasses::classB &w)
{
return v.u < w.u;
}
//} //<- and uncomment this
using var_t = std::variant<myClasses::classA, myClasses::classB>;
int main()
{
std::set<var_t> myset;
myset.emplace(myClasses::classB(1));
myset.emplace(myClasses::classA(2));
return 0;
}
If you put the operator<s in the namespace myClasses it compiles fine.
Can someone explain to me, why my original attempt failed? If I just compare
myClasses::classA(1) < myClasses::classA(2), there's no need to put the operators in the myClasses namespace.
Thank you very much in advance.
This is an feature of argument dependent lookup (ADL), which you are relying on when the operator is search for from std::variant.
When searching for free functions, including overloaded operators, the compiler will only search in namespaces related to the arguments to the function in question.
There are more details in this cppreference article.
Where you call the comparison directly from your code, at the same namespace scope as the operator< declarations, "normal" (i.e. non-ADL) lookup can find the operator definition directly.
I have an arithmetic custom type with a to_string() member. I'm thinking about overloading std::to_string in the std namespace for the type, but would this count as namespace pollution?
EDIT:
I'm thinking about this, so that this expression SFINAE would work for the type:
-> decltype(std::to_string(std::declval<T>()), void(0))
As Some programmer dude pointed out in the comment, you cannot add declarations into std namespace in this case.
Like this post, a workaround is to write your to_string in the same namespace as your custom class, and use using std::to_string to bring std::to_string in overload resolution when you want to use to_string for generic type. The following is an example:
#include <string>
struct A {};
std::string to_string(A) {return "";}
namespace detail { // does not expose "using std::to_string"
using std::to_string;
template <typename T>
decltype(to_string(std::declval<T>()), void(0)) foo() {}
}
using detail::foo;
int main()
{
foo<int>(); // ok
foo<A>(); // ok
// to_string(0); // error, std::to_string is not exposed
}
Stacked people.
Iam trying to implement an observer(esque?) pattern for my program. I have a component which stores what functions should be called if an event occours. My prolem is that i dont know how should i erase my function from the container, if the need arises. Tried storing the functions by reference, but iam not sure how to do that(or if thats possible.)
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
enum class EVENT_TYPE{
anEvent
};
class EventableComponent{
map<EVENT_TYPE, vector<function<void()>>> listeners;
public:
void trigger(EVENT_TYPE _et){
for(auto& it : listeners[_et]){
it();
}
}
void registerListener(EVENT_TYPE _et, function<void()> _fn){
listeners[_et].push_back(_fn);
};
void removeListener(EVENT_TYPE _et, function<void()> _fn){
//error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::function<void (void)>'
//(or there is no acceptable conversion)
listeners[_et].erase(remove(listeners[_et].begin(), listeners[_et].end(), _fn), listeners[_et].end());
};
};
int main(){
EventableComponent ec;
// this would become a member function for a class somewhere down the line
auto fn = [](){cout << "Hello.\n"; };
ec.registerListener(EVENT_TYPE::anEvent, fn);
ec.trigger(EVENT_TYPE::anEvent);
ec.removeListener(EVENT_TYPE::anEvent, fn);
ec.trigger(EVENT_TYPE::anEvent);
cin.get();
return 0;
};
Your problem can be reduced to the fact that two std::function instances cannot be compared for equality. std::remove requires operator==, and std::function does not have it. See "Why is std::function not equality comparable?".
Consider the following situation.
Let's say you defined two lambdas in your main:
auto fn = [](){cout << "Hello.\n"; };
auto fn2 = [](){cout << "Hello.\n"; };
Now, are those two equal or not? They do the same thing, but perhaps this is sheer coincidence. Would they become unequal if the second "Hello" became "Hello2"? Would they become unequal if the second one was no longer a lambda but a real function void f()?
The thing is that there can be no generally useful definition of equality for function objects, so it's up to you to define what equality really means in the context of your program.
You have several options to solve the problem at hand. One would be to operate on pointers to std::function objects. Pointers can be compared, and proper use of std::unique_ptr makes sure that deallocation is handled correctly.
Or you assign an identifier to every std::function you use. See the following modified example of your code in which direct storage of std::function<void()> in the vector is replaced with a custom type EventFunction that maps an int to the function object. The example uses std::remove_if to compare only the ints:
#include <map>
#include <vector>
#include <iostream>
#include <algorithm>
#include <functional>
using namespace std;
enum class EVENT_TYPE{
anEvent
};
struct EventFunction {
function<void()> f;
int id;
};
class EventableComponent{
map<EVENT_TYPE, vector<EventFunction>> listeners;
public:
void trigger(EVENT_TYPE _et){
for(auto& it : listeners[_et]){
it.f();
}
}
void registerListener(EVENT_TYPE _et, EventFunction _fn){
listeners[_et].push_back(_fn);
};
void removeListener(EVENT_TYPE _et, int function_id){
//error C2678: binary '==' : no operator found which takes a left-hand operand of type 'std::function<void (void)>'
//(or there is no acceptable conversion)
listeners[_et].erase(remove_if(listeners[_et].begin(), listeners[_et].end(),
[&](EventFunction const& e) { return e.id == function_id; }), listeners[_et].end());
};
};
int main(){
EventableComponent ec;
// this would become a member function for a class somewhere down the line
auto fn = [](){cout << "Hello.\n"; };
ec.registerListener(EVENT_TYPE::anEvent, EventFunction{ fn, 1 });
ec.trigger(EVENT_TYPE::anEvent);
ec.removeListener(EVENT_TYPE::anEvent, 1);
ec.trigger(EVENT_TYPE::anEvent);
};
Tried storing the functions by reference, but iam not sure how to do
that(or if thats possible.)
It's not possible because you cannot store references in standard-library containers. But I suppose the idea is similar to the one with pointers I mentioned above.
I'm writing some template code to determine if a given type can be passed as any argument to any available overload of a function. In the example below I've used the log function, but I've also tried this code on others in the math library, and the results are the same. The idea is to use function overloading and the sizeof operator to distinguish between cases where the type in question can legally be passed to the function in question (log, in this example).
If it worked, we'd have sizeof(overload<type>(NULL)) == sizeof(True) when 'type' can be legally passed to log, and sizeof(overload<type>(NULL)) == sizeof(False) otherwise. This does seems to work for most types, but fails for std::string.
Here's exactly how it fails:
Under normal circumstances we have sizeof(overload<std::string>(NULL)) == sizeof(False), as we should. But, when I declare an overload of log that does take a string, it still doesn't trigger the sizeof(True) branch of the logic. Note that I don't actually want to declare log(std::string) function, I'm just testing this code to make sure that it's able to detect all possible overloads.
At first I thought it just wasn't detecting overloads properly, but when I tried it with a user-defined class ('MyClass' in the example below), it worked fine: it produced sizeof(True) when log(MyClass) was declared, and sizeof(False) otherwise.
#include <iostream>
#include <math.h>
template<int>
struct TakesInt{};
struct True
{
};
struct False
{
// guarantees that sizeof(False) != sizeof(True)
True array[2];
};
// takes anything; fall back if no match can be found
template<typename T>
False overload(...);
// takes a specific type; does not actually call log
template<typename T>
True overload(TakesInt<sizeof(log(T()))>*);
// As a test, this is an overload of log that takes a string.
// I don't actually want to implement this, but it should make the compiler
// think that a string is a valid argument.
double log(std::string);
// a placeholder for user defined class; could really be anything,
// like an arbitrary number class
struct MyClass{};
// declaring log for the arbitrary class above
// note that this is the same as for the log(std::string)
// if one works, the other should
double log(MyClass);
int main()
{
std::cout << sizeof(True) << '\t' << sizeof(False) << std::endl;
std::cout << sizeof(overload<std::string>(NULL)) << std::endl;
std::cout << sizeof(overload<double>(NULL)) << std::endl;
std::cout << sizeof(overload<MyClass >(NULL)) << std::endl;
return 0;
}
Here's the same issue w/o the SFINAE distraction:
#include <iostream>
namespace ns
{
struct string {};
}
void bar(...) { std::cout << "void bar(...)\n"; }
template<class T>
void foo()
{
T x{};
bar(x);
}
void bar(ns::string) { std::cout << "void bar(ns::string)\n"; }
int main()
{
foo<int>();
foo<ns::string>();
}
Output:
void bar(...)
void bar(...)
Lookup of a dependent function name will be performed:
as (pure) unqualified lookup from the point of definition
as (pure) argument-dependent lookup from the point of instantiation
Therefore, the following example differs:
#include <iostream>
namespace ns
{
struct string {};
}
void bar(...) { std::cout << "void bar(...)\n"; }
template<class T>
void foo()
{
T x{};
bar(x);
}
namespace ns
{
void bar(ns::string) { std::cout << "void bar(ns::string)\n"; }
}
int main()
{
foo<int>();
foo<ns::string>();
}
Output:
void bar(...)
void bar(ns::string)
For std::string, the only associated namespace is std. The global namespace is not associated and will not be searched in the OP's code. Therefore, the overload declared after the template definition will not be found.
N.B. Please do not inject overloads into namespace std. This will lead to undefined behaviour as per [namespace.std]/1.