我希望能够在C ++中执行以下操作
在阅读了很长很复杂的代码之后,我不清楚这样做的简单方法是什么。 C ++ 11解决方案很好。但是代码有时需要使用旧的boost版本(1.39.0)进行编译,这正是为什么需要这种解决方法的原因。
目前我通过在检查BOOST_VERSION
宏后创建方法别名来实现。但是,了解更复杂的替代方案可能适用于更一般的情况会很好。
答案 0 :(得分:2)
这是一个可以解决的问题。
我发现这样做的唯一方法是污染名称空间boost::filesystem
和boost::filesystem3
,然后测试原始函数是否存在。我知道这不是有史以来最好的事情,但是在日常生活中完成并运行是妥协。
两个命名空间中都存在两个copy
版本。它们被声明为:
void copy(const path& from, const path& to);
void copy(const path& from, const path& to, system::error_code& ec);
请注意,我在下面的示例中使用稍微不同的形式重新声明了它们,以简化操作并避免在示例代码中使用boost。
这是一个最小的工作示例:
#include<iostream>
#include<type_traits>
// original namespaces
namespace boost { namespace filesystem {
void copy(int, char) { std::cout << "b::f::copy" << std::endl; }
void copy(int, char, double) {}
// ... everything else ...
}}
namespace boost { namespace filesystem3 {
void copy(int, char) { std::cout << "b::f3::copy" << std::endl; }
void copy(int, char, double) {}
// ... everything else ...
}}
// pollution
namespace boost { namespace filesystem {
struct tag {};
void copy(tag, tag) {}
}}
namespace boost { namespace filesystem3 {
struct tag {};
void copy(tag, tag) {}
}}
std::true_type test(int, void(*)(int, char));
std::false_type test(...);
constexpr bool has_filesystem_copy = decltype(test(0, &boost::filesystem::copy))::value;
constexpr bool has_filesystem3_copy = decltype(test(0, &boost::filesystem3::copy))::value;
template<bool = true>
struct fallback_fn {};
template<>
struct fallback_fn<has_filesystem3_copy> {
template<typename... Args>
static void invoke(Args... args) {
boost::filesystem3::copy(args...);
}
};
template<bool = true>
struct copy_fn: fallback_fn<> {};
template<>
struct copy_fn<has_filesystem_copy> {
template<typename... Args>
static void invoke(Args... args) {
boost::filesystem::copy(args...);
}
};
int main() {
copy_fn<>::invoke(0, 'c');
}
随意使用标记为原始名称空间的名称空间中的函数。
总结一下:
如果copy
和boost::filesystem
同时提供boost::filesystem3
,则会选择前者。请参阅wandbox。
如果copy
仅在boost::filesystem
中可用,则会将其取消。请参阅wandbox。
如果copy
仅在boost::filesystem3
中可用,则会将其取消。请参阅wandbox。
如果copy
根本不可用,则会出现如下编译时错误:
'invoke'不是'copy_fn&lt;&gt;'
的成员
在wandbox上查看。
为此,我使用了模板特化规则和几个constexpr
变量
请注意,如果您愿意,可以避免包含<type_traits>
:
constexpr bool test(int, void(*)(int, char)) { return true; }
constexpr bool test(...) { return false; }
constexpr bool has_filesystem_copy = test(0, &boost::filesystem::copy);
constexpr bool has_filesystem3_copy = test(0, &boost::filesystem3::copy);
同样,污染命名空间并不是你能想到的最好的想法。无论如何,只要你通过像copy
这样的实用程序类调用copy_fn
,它就可以在这种情况下起作用。
作为旁注,请记住,如果您必须 wrap 多个函数,那么它非常烦人并且容易出错。如果我只查看你问题的文字,情况并非如此,但我不知道真实情况是什么。
答案 1 :(得分:1)
这里的另一个想法是(大部分)诀窍:
storm.zookeeper.servers:
- "10.0.xx.xxx"
storm.zookeeper.port: 2181
nimbus.seeds: ["10.0.xxx.xxx"]
storm.local.dir: "/storm/datadir"
一些警告:命名空间必须实际存在,但您始终可以将它们定义为空。测试的函数不得存在于具有兼容参数的全局范围内。特别是,您无法将我的上一个#include <tuple>
#include <utility>
#include <iostream>
namespace fake_boost {
namespace filesystem {
// class path { public:
// template<typename Source> path(Source const&) {}
// };
// void copy( const path&, const path& )
// { std::cout << "fake_boost::filesystem::copy\n"; }
}
namespace filesystem3 {
class path { public:
template<typename Source> path(Source const&) {}
};
void copy( const path&, const path& )
{ std::cout << "fake_boost::filesystem3::copy\n"; }
}
}
namespace test_copy {
template <typename...> using void_t = void; // or use C++17 std::void_t
namespace test_filesystem3 {
using namespace fake_boost::filesystem3;
template <typename... Args>
void do_copy(Args&& ... args)
{ copy(std::forward<Args>(args)...); }
}
namespace test_filesystem {
template <typename Tuple, typename Enable=void>
struct copy_switcher {
template <typename... Args>
static void do_copy(Args&& ... args)
{ test_filesystem3::do_copy(std::forward<Args>(args)...); }
};
using namespace fake_boost::filesystem;
template <typename... Args>
struct copy_switcher<std::tuple<Args...>,
void_t<decltype(copy(std::declval<Args&&>()...))>> {
static void do_copy(Args&& ... args)
{ copy(std::forward<Args>(args)...); }
};
}
}
template <typename... Args>
void do_copy(Args&& ... args) {
test_copy::test_filesystem::copy_switcher<std::tuple<Args...>>
::do_copy(std::forward<Args>(args)...);
}
int main() {
do_copy( "from.txt", "to.txt" );
}
重命名为do_copy
。