[英]Getting the number of arguments to a function at compile-time using variadic templates with argument type check in c++
說我有一節課:
template<typename... Types>
class Example
{
public:
using types = std::tuple<Types...>;
template<size_t N> using dim_type = std::tuple_element_t<N, types>;
};
我想實現一個依賴於元組元素的成員函數,如下所示,目標是在編譯期間訪問參數的數量:
template<size_t N>
inline constexpr void do_stuff(const dim_type<N>& elems...)
{
constexpr size_t size_stuff = sizeof...(elems); // <-- this is the end goal
};
問題是do_stuff()
這種實現不會這樣做。 最終我希望這個功能像這樣工作:
Example<long,std::string> ex;
ex.do_stuff<0>(3);
ex.do_stuff<0>(5,6);
ex.do_stuff<1>("a","b","c","d");
ex.do_stuff<0>("a","b","c","d"); // <-- this line should not compile
ex.do_stuff<1>(1,"b"); // <-- nor should this one
在do_stuff
我應該在編譯時知道傳遞了多少個參數。
一個可能的答案,但我遇到了問題:
我認為正確實現這一點需要使用可變參數模板,但是,我在使std::enable_if
部分工作時遇到問題:
template<size_t N, typename... Args,
std::enable_if_t<static_and<std::is_convertible_v<Args, dim_type<N>>...>::value>* = nullptr>
inline constexpr void do_stuff(const Args&... elems)
{
constexpr size_t size_stuff = sizeof...(elems); // <-- this is the end goal
};
其中static_and
是:
template<bool Head, bool... Tail>
struct static_and {
static constexpr bool value = Head && static_and<Tail...>::value;
};
template<bool Bool> struct static_and<Bool> {
static constexpr bool value = Bool;
};
在我看來,正確的方式(一種可能的正確方式)是基於static_and
:一個可變參數類型列表Args
被SFINAE檢查為可轉換為正確的類型。
我提出了以下版本的static_and
template <bool ...>
struct static_and : public std::false_type
{ };
template <>
struct static_and<> : public std::true_type
{ };
template <bool ... Bs>
struct static_and<true, Bs...> : public static_and<Bs...>
{ };
和do_stuff()
成為
template <std::size_t I, typename ... Ts>
inline constexpr auto do_stuff (Ts const & ... elems)
-> std::enable_if_t<
static_and<std::is_convertible<Ts, type_n<I>>::value...>::value>
{
// now the number of elems is sizeof...(elems)
// or sizeof...(Ts)
std::cout << sizeof...(Ts) << std::endl;
}
以下是完整的編譯示例(適當時出現編譯錯誤)
#include <tuple>
#include <iostream>
#include <type_traits>
template <bool ...>
struct static_and : public std::false_type
{ };
template <>
struct static_and<> : public std::true_type
{ };
template <bool ... Bs>
struct static_and<true, Bs...> : public static_and<Bs...>
{ };
template <typename ... Types>
struct foo
{
using types = std::tuple<Types...>;
static constexpr std::size_t num_types { sizeof...(Types) };
template <std::size_t I>
using type_n = std::tuple_element_t<I, types>;
template <std::size_t I, typename ... Ts>
inline constexpr auto do_stuff (Ts const & ... elems)
-> std::enable_if_t<
static_and<std::is_convertible<Ts, type_n<I>>::value...>::value>
{
// now the number of elems is sizeof...(elems)
// or sizeof...(Ts)
std::cout << sizeof...(Ts) << std::endl;
}
};
int main ()
{
foo<long, std::string> ex;
ex.do_stuff<0>(3); // compile; print 1
ex.do_stuff<0>(5, 6); // compile; print 2
ex.do_stuff<1>("a", "b", "c", "d"); // compile; print 4
// ex.do_stuff<0>("a", "b", "c", "d"); // compilation error
// ex.do_stuff<1>(1, "b"); // compilation error
}
如果你可以使用C ++ 17而不是static_and
你可以簡單地使用模板折疊
template <std::size_t I, typename ... Ts>
inline constexpr auto do_stuff (Ts const & ... elems)
-> std::enable_if_t<(... && std::is_convertible<Ts, type_n<I>>::value)>
{
// now the number of elems is sizeof...(elems)
// or sizeof...(Ts)
std::cout << sizeof...(Ts) << std::endl;
}
如果在C ++ 14中,你更喜歡constexpr
static_and()
函數而不是struct
,你可以按如下方式編寫它
template <bool ... Bs>
constexpr bool static_and ()
{
using unused = bool[];
bool ret { true };
(void) unused { true, ret &= Bs... };
return ret;
}
所以do_stuff()
成了
template <std::size_t I, typename ... Ts>
inline constexpr auto do_stuff (Ts const & ... elems)
-> std::enable_if_t<
static_and<std::is_convertible<Ts, type_n<I>>::value...>()>
{
// now the number of elems is sizeof...(elems)
// or sizeof...(Ts)
std::cout << sizeof...(Ts) << std::endl;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.