![](/img/trans.png)
[英]C++ - Determine instance of foo in templated function pointer argument call
[英]How to determine if function argument is a sequence in C++?
在通過auto
生成的數據結構編寫簡單遍歷的過程中,我想知道為什么type_traits
不提供類似std::is_sequence
的東西。
我正在使用這個make_array
:
template <typename... T>
constexpr auto make_array(T&&... values)
-> std::array< typename std::decay< typename std::common_type<T...>::type>::type, sizeof...(T)> {
return {std::forward<T>(values)...};
}
創建這樣的結構:
auto z = make_array(
make_array('h','e','l','l','o'),
make_array('w','o','r','l','d')
);
元素也可以具有不同的類型和尺寸。
稍后我想支持更復雜的用途,例如func(1,2,MyClass(3),4.0,make_array(5,6,7),std::make_tuple(8.0,"9.1011",12))
,
或func({13,14,15})
,但我認為這是第二步。
(這些想法是否會進入我的項目我還不知道,我只是好奇。)
我的方法是編寫兩個重載的模板函數func
:
template<typename T>
typename std::enable_if<!is_sequence<T>::value, void>::type
func(T& t) {
std::cout << "\n\tfunc(t) => " << t << ' ';
}
template<typename SeqT>
typename std::enable_if<is_sequence<SeqT>::value, void>::type
func(SeqT& s) {
std::cout << "\nfunc(SeqT& s)...";
for(auto iter=std::begin(s);iter!=std::end(s);++iter) func(*iter);
std::cout << "\n...func(SeqT& s)...";
}
並在
template <typename T>
class is_sequence {
private:
typedef char YesType[1];
typedef char NoType[2];
template <typename C> static YesType& test(decltype(std::begin(C{})));
template <typename C> static NoType& test(...);
public:
enum { value = sizeof(test<T>(0)) == sizeof(YesType) };
};
(從這里偷來的想法)
它似乎工作:
func(z);
印刷
func(SeqT& s)...
func(SeqT& s)...
func(t) => h
func(t) => e
func(t) => l
func(t) => l
func(t) => o
...func(SeqT& s)
func(SeqT& s)...
func(t) => w
func(t) => o
func(t) => r
func(t) => l
func(t) => d
...func(SeqT& s)
...func(SeqT& s)
我的問題來了:
(1) 我不認為我的需要和一般方法太特殊。 但是明智的 C++ 家伙顯然沒有看到需要將is_sequence
之類的東西放入標准中。 我在這里想念什么?
(2) 你對我還有什么建議?
謝謝你們的評論。
我知道我的 C++ 習語看起來已經過時了。 除此之外,我還學習了基於 C++98 的“現代 C++ 編程”,我仍然看到我的大多數客戶都在猶豫是否允許自 C++11 以來引入的最新概念。 我決定暫時堅持使用 C++17...
我想提出我的第二步正在進行的工作結果。
一組重載函數func(..)
支持std::tuple
,當然,術語“序列”似乎比范圍更值得懷疑。
我添加了一些對constexpr
的支持,通過一組constexpr
模板 function 重載count(..)
來證明,它們每個都返回子樹中的葉子數(我希望這個詞在上下文中足夠清楚)。
另一個注意事項:此處不將字符串視為序列。
您可以在下面找到完整的程序,使用 gcc 和 --std=c++17 編譯。 當然歡迎大家評論。。。
#include <iostream>
#include <utility>
#include <type_traits>
#include <algorithm>
#include <array>
#include <tuple>
#include <vector>
template <typename... T>
constexpr auto make_array(T&&... values)
-> std::array< typename std::decay< typename std::common_type<T...>::type>::type, sizeof...(T)> {
return {std::forward<T>(values)...};
}
template <typename T>
struct is_seq {
template <typename U>
static auto helper(U t) -> decltype(std::begin(t),std::true_type{}) {return{};}
static auto helper(...) -> std::false_type { return{};}
static const bool value = decltype(helper(std::declval<T>()))::value;
};
template <typename T>
struct is_tuple {
template <typename U,int ix=0>
static auto helper(U t) -> decltype(std::get<ix>(t),std::true_type{}) {return{};}
static auto helper(...) -> std::false_type { return{};}
static const bool value = decltype(helper(std::declval<T>()))::value;
};
template<typename T>
typename std::enable_if<(!is_seq<T>::value) and (!is_tuple<T>::value) , void>::type
func(T& t) {
std::cout << '<' << t << '>';
}
template<typename SeqT>
typename std::enable_if<is_seq<SeqT>::value, void>::type
func(SeqT& s) {
std::cout << "\nfunc(SeqT& s)...";
for(auto iter=std::begin(s);iter!=std::end(s);++iter) func(*iter);
std::cout << "\n...func(SeqT& s)";
}
template<typename SeqT>
typename std::enable_if<is_seq<SeqT>::value, void>::type
func(const SeqT& s) {
std::cout << "\nfunc(const SeqT& s)...";
for(auto iter=std::begin(s);iter!=std::end(s);++iter) func(*iter);
std::cout << "\n...func(const SeqT& s)";
}
template<class ...TL>
void func(const std::tuple<TL...>& tp) {
std::cout << "\nfunc(const tuple<TL>& tp)...";
std::apply([](auto&&... args) {(...,func(args));}, tp);
std::cout << "\n...func(const tuple<TL>& tp)";
}
template<typename T>
void func(std::initializer_list<T> il) {
std::cout << "\nfunc(il)...";
for(auto iter=il.begin();iter!=il.end();++iter) func(*iter);
std::cout << "\n...func(il)";
}
template<typename ...TL>
void func(const TL&... tl) {
std::cout << "\nfunc(t,tl)... ";
(...,func(tl));
std::cout << "\n...func(t,tl)";
}
void func(...) {
std::cout << "func(...)";
}
template<class ...TL>
constexpr std::size_t count(const std::tuple<TL...>& tp) ;
template<typename T>
constexpr typename std::enable_if<(!is_seq<T>::value) and (!is_tuple<T>::value) , std::size_t>::type
count(const T& /*t*/) {
return 1;
}
constexpr std::size_t count(const std::string& ) {
return 1;
}
template<typename SeqT>
constexpr typename std::enable_if<is_seq<SeqT>::value, std::size_t>::type
count(const SeqT& s) {
std::size_t result(0);
for(auto iter=std::begin(s);iter!=std::end(s);++iter) {
result += count(*iter);
}
return result;
}
template <size_t I = 0, typename... Ts>
constexpr typename std::enable_if<I == sizeof...(Ts), std::size_t>::type
countImpl(const std::tuple<Ts...>& /*tup*/) {
return 0;
}
template <size_t I = 0, typename... Ts>
constexpr typename std::enable_if<(I < sizeof...(Ts)),std::size_t>::type
countImpl(const std::tuple<Ts...>& tup) {
return count(std::get<I>(tup)) + countImpl<I + 1>(tup);
}
template<class ...TL>
constexpr std::size_t count(const std::tuple<TL...>& tp) {
return countImpl(tp);
}
template<typename T>
std::size_t count(std::initializer_list<T> il) {
std::size_t result(0);
for(auto iter=il.begin();iter!=il.end();++iter) {
result += count(*iter);
}
return result;
}
template<typename ...TL>
constexpr std::size_t count(const TL&... tl) {
std::size_t result(0);
result = ( ... + count(tl) ) ;
return result;
}
constexpr std::size_t count(...) {
return 0;
}
struct X {};
std::ostream& operator<<(std::ostream& os, const X& ) {
os << "X{}";
return os;
}
#define TEST(x) { std::cout << "\n" << #x << ":\t" ; x ;}
#define TEST2(x) { std::cout << "\n" << #x << ":\t" << x ;}
int main(int , char** argv) {
std::cout << "\nthis is " << argv[0] << " running ...";
std::array<double,13> da;
auto t=std::make_tuple("hello",1,"world",3.1415);
TEST(func(1))
TEST(func())
TEST(func(t))
TEST(func(std::array<int,19>{11,12,13}))
TEST(func(da))
TEST(func(X()))
TEST(func(1,2,3))
TEST(func(X{},X()))
TEST(func({'a','b','c'}))
auto z = make_array(
make_array('h','e','l','l','o'),
make_array('w','o','r','l','d')
);
TEST(func(z))
TEST(func(
make_array('h','e','l','l','o'),
std::vector<std::string>{"very","very"},
std::make_tuple('c','o',make_array('o','l')),
make_array('w','o','r','l','d','!')
));
std::cout << "\n";
TEST2(count(1,2,3,4));
constexpr auto c1 = count(1,2,3,4);
std::cout << "\nconstexpr auto c1 = count(1,2,3,4):" << c1;
std::cout << "\n\n";
constexpr auto c2 = count(
make_array('h','e','l','l','o'),
make_array("very","(very)"),
std::make_tuple('c','o',make_array('o','l')),
make_array("world","!!")
);
std::cout << "\ncount(...):" << c2;
std::cout << "\n...bye\n";
return 0;
}
它打印:
this is ./sfinae-is-sequence.exe running ...
func(1):
func(t,tl)... <1>
...func(t,tl)
func(): func(...)
func(t):
func(const tuple<TL>& tp)...<hello><1><world><3.1415>
...func(const tuple<TL>& tp)
func(std::array<int,19>{11,12,13}):
func(const SeqT& s)...<11><12><13><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0><0>
...func(const SeqT& s)
func(da):
func(SeqT& s)...<0><0><0><0><0><0><0><0><0><0><0><0><0>
...func(SeqT& s)
func(X()):
func(t,tl)... <X{}>
...func(t,tl)
func(1,2,3):
func(t,tl)... <1><2><3>
...func(t,tl)
func(X{},X()):
func(t,tl)... <X{}><X{}>
...func(t,tl)
func({'a','b','c'}):
func(il)...<a><b><c>
...func(il)
func(z):
func(SeqT& s)...
func(SeqT& s)...<h><e><l><l><o>
...func(SeqT& s)
func(SeqT& s)...<w><o><r><l><d>
...func(SeqT& s)
...func(SeqT& s)
func( make_array('h','e','l','l','o'), std::vector<std::string>{"very","very"}, std::make_tuple('c','o',make_array('o','l')), make_array('w','o','r','l','d','!') ):
func(t,tl)...
func(const SeqT& s)...<h><e><l><l><o>
...func(const SeqT& s)
func(const SeqT& s)...
func(const SeqT& s)...<v><e><r><y>
...func(const SeqT& s)
func(const SeqT& s)...<v><e><r><y>
...func(const SeqT& s)
...func(const SeqT& s)
func(const tuple<TL>& tp)...<c><o>
func(const SeqT& s)...<o><l>
...func(const SeqT& s)
...func(const tuple<TL>& tp)
func(const SeqT& s)...<w><o><r><l><d><!>
...func(const SeqT& s)
...func(t,tl)
count(1,2,3,4): 4
constexpr auto c1 = count(1,2,3,4):4
count(...):13
...bye
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.