如何创建一个接受相同数量的字符串的函数 - int - char
func("aa","sd","zzz",123,13,3,'w','a','x') //correct
func("aa","sd",123,3,'w','x') //correct
func("aa",2,'w') //correct
func()//correct
func("aa","VV",23,'w') //error because 2 string 1 int and 1 char
func('a',2) //error 0 string 1 char 1 int
.....
我想在编译时检查变量而不是在运行时检查变量,因此我无法使用std::vector
。
任何想法?有可能吗?
答案 0 :(得分:4)
假设您的参数如下所示:
struct Param
{
string mS;
char mC;
int mN;
};
不要试图组合一个带有未知或可变数量参数的函数,而是让函数取vector
。
void func (const vector <Param>& parameters)
更好的是,让函数将一对迭代器带到所述向量:
void func (vector <Param>::const_iterator begin, vector <Param>::const_iterator end)
更好的是,对容器和迭代器进行泛化:
template <typename Iterator> void func (Iterator begin, Iterator end)
在最后一种情况下,迭代器可以引用符合迭代器限制的任何东西。这包括C风格的数组。您可以这样使用:
void Doer()
{
Params params[] =
{
Param("aa",123, 'W'),
Param("sd",13,'a'),
Param("zzz",3,'x')
};
const size_t numParams = sizeof (params) / sizeof (params[0]);
func (params, params + numParams);
}
当然你需要一个构造函数:
struct Param
{
Param (const std::string s, int n, char c)
:
mS (s),
mN (n),
mC (c)
{
}
// ...
};
在某些情况下,您可能需要制造商类型功能:
Param make_param (const std::string& s, int n, char c)
{
Param retval (s, n, c);
return retval;
}
答案 1 :(得分:4)
(这个问题最初被标记为C和C ++; C标签后来被删除了。以下部分内容特定于C,但是我将它留在这里,以防它对其他人有用。)
在C中,不,我不相信用编译时检查可以做到这一点。变量函数(a)至少需要一个固定参数(消除func()
示例),以及(b)不在编译时检查可变参数的类型。 Variadic宏(C99中的新增功能)可能更有前途,但它们不执行类型检查。我已经考虑过如何使用嵌套通用选择(C11中的一个新功能,C ++中不存在),但我不相信它们可以解决问题。
如果你正在使用C(这个问题最初被标记为C和C ++),我认为你能得到的最接近的是为每个参数提供一个独特的函数:
void func0(void);
void func1(char*, int, char);
void func2(char*, char*, int, int, char, char);
void func3(char*, char*, char*, int, int, int, char, char, char);
你知道你在写电话时你传递了多少参数,所以指定一个不同的功能并不是太大的负担。
在C ++中,您可以提供多个重载函数,每个函数都接受相应类型的参数:
void func();
void func(char*, int, char);
void func(char*, char*, int, int, char, char);
void func(char*, char*, char*, int, int, int, char, char, char);
依此类推,因为你有耐心等多少过载。
这些解决方案都无限期地可扩展到任意数量的参数。
我原本以为C ++中没有通用解决方案,但Jarod42's answer(我还没有花时间去理解)似乎已经显示出来了。另一方面,为简单起见,有一些事情要说。另一方面,你只需要写一次。
还有一件事:你的最后一个例子是:
func('a',2) //error 0 string 1 char 1 int
在C中,'a'
和2
属于同一类型,即int
。在C ++中,a
的类型为char
。 (同样,如果你只关心C ++,这不一定是相关的。)
答案 2 :(得分:2)
C ++ 11中的一个简单方法是:
template <std::size_t N>
void func(const std::array<const char*, N>& cstrings,
const std::array<int, N>& ints
const std::array<char, N>& chars);
所以你可以使用它:
func({ "aa","sd","zzz"}, {123, 13, 3} , {'w', 'a', 'x'});
如果你想使用相同的语法,它更详细并使用SFINAE:
它回退到用std::array
调用版本,因为它更方便实现
#include <cstdint>
#include <array>
#include <tuple>
#include <type_traits>
#if 1 // Not in C++11
template <std::size_t ...> struct index_sequence {};
template <std::size_t I, std::size_t ...Is>
struct make_index_sequence : make_index_sequence < I - 1, I - 1, Is... > {};
template <std::size_t ... Is>
struct make_index_sequence<0, Is...> : index_sequence<Is...> {
typedef index_sequence<Is...> type;
};
#endif
template <std::size_t N>
void func(const std::array<const char*, N>& cstrings,
const std::array<int, N>& ints
const std::array<char, N>& chars)
{
// Add your code here
}
namespace detail
{
template <typename T, typename SEQ, typename SEQ2> struct helper_split3;
template <typename ... Ts, std::size_t ... Is, std::size_t ... Is2>
struct helper_split3<std::tuple<Ts...>, index_sequence<Is...>, index_sequence<Is2...> >
{
typedef std::tuple<typename std::tuple_element<Is, std::tuple<Ts...> >::type...> First;
typedef std::tuple<typename std::tuple_element<sizeof...(Is) + Is, std::tuple<Ts...> >::type...> Middle;
typedef std::tuple<typename std::tuple_element<2 * sizeof...(Is) + Is2, std::tuple<Ts...> >::type...> Last;
};
template <typename T, typename ... Ts> struct are_same : std::true_type {};
template <typename T, typename Tail, typename ... Ts>
struct are_same<T, Tail, Ts...> :
std::conditional<std::is_same<T, Tail>::value && are_same<T, Ts...>::value,
std::true_type, std::false_type>::type {};
template <typename T, typename Tuple> struct are_same_in_tuple;
template <typename T, typename ... Ts>
struct are_same_in_tuple<T, std::tuple<Ts...>> : are_same<T, Ts...> {};
template<typename ... Ts>
struct func_trait
{
typedef helper_split3<std::tuple<Ts...>,
typename make_index_sequence<sizeof...(Ts) / 3>::type,
typename make_index_sequence<sizeof...(Ts) - 2 * (sizeof...(Ts) / 3)>::type>
helper;
static const bool value = (sizeof...(Ts) % 3 == 0)
&& are_same_in_tuple<const char*, typename helper::First>::value
&& are_same_in_tuple<int, typename helper::Middle>::value
&& are_same_in_tuple<char, typename helper::Last>::value;
};
template <typename ... Ts, std::size_t ... Is>
void func(std::tuple<Ts...>&& t, index_sequence<Is...>)
{
constexpr std::size_t N = sizeof...(Ts);
::func<N>(std::array<const char*, N>({std::get<Is>(t)...}),
std::array<int, N>({std::get<sizeof...(Is) + Is>(t)...}),
std::array<char, N>({std::get<2 * sizeof...(Is) + Is>(t)...}));
}
} // namespace detail
template <typename ... Ts>
typename std::enable_if<detail::func_trait<Ts...>::value, void>::type
func(Ts...args)
{
detail::func(std::tie(args...), make_index_sequence<sizeof...(Ts) / 3>());
}
答案 3 :(得分:1)
在C和C ++中,在编写variadic functions时,有三大规则:
这就像printf
之类的功能一样
它的第一个参数始终为char*
下一组参数由找到的%x
格式器决定
当它到达最后一个Percent-specifier时,它知道它的参数。
如果您可以遵循这三条规则,那么任何编写可变函数的在线指南都将帮助您完成您所追求的目标。
答案 4 :(得分:-1)
你不能按照你的要求这样做。你最好的选择是制作一个包含这三种类型的结构类型,然后传入可变数量的结构。