簡體   English   中英

如何確定 function 參數是否是 C++ 中的序列?

[英]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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM