C++ 别名到标准类型的自定义点
假设我正在C++ 别名到标准类型的自定义点,c++,templates,argument-dependent-lookup,customization-point,C++,Templates,Argument Dependent Lookup,Customization Point,假设我正在lib命名空间中编写一些通用算法,用于调用自定义点my_func 第一次尝试是将ADL用于my_func 其中一个用户想专门为他的类型指定my_func,这是std类型的别名。当然,在他的名称空间中定义它是行不通的,因为ADL对alias不起作用。标准不允许在std命名空间中定义它。剩下的唯一选项似乎是在算法的名称空间lib中定义。但是,如果最终用户在包含自定义头之前包含算法头,那么这也不起作用 #include <iostream> #include <array&
lib
命名空间中编写一些通用算法,用于调用自定义点my_func
第一次尝试是将ADL用于my_func
其中一个用户想专门为他的类型指定my_func
,这是std
类型的别名。当然,在他的名称空间中定义它是行不通的,因为ADL对alias不起作用。标准不允许在std
命名空间中定义它。剩下的唯一选项似乎是在算法的名称空间lib
中定义。但是,如果最终用户在包含自定义头之前包含算法头,那么这也不起作用
#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{});
}
为什么这个问题与第一个问题(原始ADL)不同?
第四个尝试是使用模板专业化,这似乎像预期的那样正常工作
#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{});
}
#包括
#包括
编写通用算法和自定义点并允许客户端自定义std类型别名的最佳方法是什么
其中一个用户想专门为他的类型指定my_func
,这是std类型的别名
这是原罪,它给你带来了所有的痛苦。C++中的类型别名只是别名;他们不是新的类型。您有一个使用自定义点的通用算法,如
// 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();
}
另一个在做什么
using IntSet = std::set<int>;
template<> struct std::hash<IntSet> {
size_t operator()(const IntSet& s) const { return s.size(); }
};
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;
}
};
使用IntSet=std::set;
模板结构std::hash{
size\u t运算符()(常量IntSet&s,size\u t h=0)常量{
对于(inti:s)h+=std::hash()(i);
返回h;
}
};
然后,当您将std::unordered_集
从一个对象文件传递到另一个对象文件时,他们都尝试使用std::unordered_集
,然后在运行时出现boom、ODR冲突和未定义的行为,他们同意std::hash
的名称,但不同意其含义。只是一大罐虫子。不要打开它。请在问题中包含相关代码
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
using IntSet = std::set<int>;
template<> struct std::hash<IntSet> {
size_t operator()(const IntSet& s) const { return s.size(); }
};
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;
}
};