String class 构造函数接受 const char* 列表
String class constructor accepting list of const char*
在我的字符串 class 中,我想制作一个接受可变长度参数 (const char*
) 的构造函数,例如带有可变参数模板的参数包。
类似以下内容
class String
{
public:
String(const char*... xList)
{
// Internally appending all const char* present in xList and
// populating String class char buffer
}
};
知道如何实现吗?
我的印象是下面的东西应该可以工作......但事实并非如此。
template <const char* ... Args>
String(Args... xList)
{
}
使用 va_arg
可能有一种方法,但我对此不感兴趣。
实现你想要的方法是采用任意类型的参数,然后使用 SFINAE 来约束它们。在 C++11/14 中,您将需要一些额外的样板代码:
template<class...>
struct conjunction : std::true_type {};
template<class B>
struct conjunction<B> : B {};
template<class B, class... Bn>
struct conjunction<B, Bn...>
: std::conditional_t<B::value, conjunction<Bn...>, B> {};
class String
{
public:
template<class... Args, typename = std::enable_if_t<
conjunction<std::is_convertible<Args, const char*>...>::value>>
String(const Args&... list)
{}
};
在 C++17 中,解决方案更短:
class String
{
public:
template<class... Args, typename = std::enable_if_t<
(std::is_convertible_v<Args, const char*> && ...)>>
String(const Args&... list)
{}
};
这是一个使用可变参数模板和 SFINAE 的工作示例,如果您不提供 const char*
s
,它将无法编译
#include <type_traits>
#include <list>
#include <iostream>
struct String
{
std::list<char> ls;
template<class ... Args, class = std::enable_if_t<std::is_same_v<std::common_type_t<Args...>, const char *>>>
String(Args...args):ls{*args...}
{
}
};
int main(){
auto c1 = 'a'; const char * pc1 = &c1;
auto c2 = 'b'; const char * pc2 = &c2;
auto c3 = 'c'; const char * pc3 = &c3;
String s{pc1, pc2, pc3};
for(auto it = s.ls.begin();it != s.ls.end(); ++it)std::cout << *it;
}
加上c++11
,代码可以这样
#include <type_traits>
#include <list>
#include <iostream>
struct String
{
std::list<char> ls;
template<class ... Args, class = typename std::enable_if<std::is_same<typename std::common_type<Args...>::type, const char *>::value>::type>
String(Args...args):ls{*args...}
{
}
};
int main(){
auto c1 = 'a'; const char * pc1 = &c1;
auto c2 = 'b'; const char * pc2 = &c2;
auto c3 = 'c'; const char * pc3 = &c3;
String s{pc1, pc2, pc3};
for(auto it = s.ls.begin();it != s.ls.end(); ++it)std::cout << *it;
}
不完全是你问的,但是......如果你接受额外的一对调用构造函数的括号,你可以按如下方式传递 char const *
的可变参数列表
struct foo
{
template <std::size_t Dim>
foo (char const * const (&arr)[Dim])
{ /* do something with arr */ }
};
缺点是不能这样调用
foo f("one", "two", "three");
但你必须加上括号
// ...V.....................V
foo f({"one", "two", "three"});
下面是一个完整的编译示例
#include <iostream>
struct foo
{
template <std::size_t Dim>
foo (char const * const (&arr)[Dim])
{
for ( auto const & str : arr )
std::cout << str << std::endl;
}
};
int main ()
{
foo f({"one", "two", "three"});
}
在我的字符串 class 中,我想制作一个接受可变长度参数 (const char*
) 的构造函数,例如带有可变参数模板的参数包。
类似以下内容
class String
{
public:
String(const char*... xList)
{
// Internally appending all const char* present in xList and
// populating String class char buffer
}
};
知道如何实现吗? 我的印象是下面的东西应该可以工作......但事实并非如此。
template <const char* ... Args>
String(Args... xList)
{
}
使用 va_arg
可能有一种方法,但我对此不感兴趣。
实现你想要的方法是采用任意类型的参数,然后使用 SFINAE 来约束它们。在 C++11/14 中,您将需要一些额外的样板代码:
template<class...>
struct conjunction : std::true_type {};
template<class B>
struct conjunction<B> : B {};
template<class B, class... Bn>
struct conjunction<B, Bn...>
: std::conditional_t<B::value, conjunction<Bn...>, B> {};
class String
{
public:
template<class... Args, typename = std::enable_if_t<
conjunction<std::is_convertible<Args, const char*>...>::value>>
String(const Args&... list)
{}
};
在 C++17 中,解决方案更短:
class String
{
public:
template<class... Args, typename = std::enable_if_t<
(std::is_convertible_v<Args, const char*> && ...)>>
String(const Args&... list)
{}
};
这是一个使用可变参数模板和 SFINAE 的工作示例,如果您不提供 const char*
s
#include <type_traits>
#include <list>
#include <iostream>
struct String
{
std::list<char> ls;
template<class ... Args, class = std::enable_if_t<std::is_same_v<std::common_type_t<Args...>, const char *>>>
String(Args...args):ls{*args...}
{
}
};
int main(){
auto c1 = 'a'; const char * pc1 = &c1;
auto c2 = 'b'; const char * pc2 = &c2;
auto c3 = 'c'; const char * pc3 = &c3;
String s{pc1, pc2, pc3};
for(auto it = s.ls.begin();it != s.ls.end(); ++it)std::cout << *it;
}
加上c++11
,代码可以这样
#include <type_traits>
#include <list>
#include <iostream>
struct String
{
std::list<char> ls;
template<class ... Args, class = typename std::enable_if<std::is_same<typename std::common_type<Args...>::type, const char *>::value>::type>
String(Args...args):ls{*args...}
{
}
};
int main(){
auto c1 = 'a'; const char * pc1 = &c1;
auto c2 = 'b'; const char * pc2 = &c2;
auto c3 = 'c'; const char * pc3 = &c3;
String s{pc1, pc2, pc3};
for(auto it = s.ls.begin();it != s.ls.end(); ++it)std::cout << *it;
}
不完全是你问的,但是......如果你接受额外的一对调用构造函数的括号,你可以按如下方式传递 char const *
的可变参数列表
struct foo
{
template <std::size_t Dim>
foo (char const * const (&arr)[Dim])
{ /* do something with arr */ }
};
缺点是不能这样调用
foo f("one", "two", "three");
但你必须加上括号
// ...V.....................V
foo f({"one", "two", "three"});
下面是一个完整的编译示例
#include <iostream>
struct foo
{
template <std::size_t Dim>
foo (char const * const (&arr)[Dim])
{
for ( auto const & str : arr )
std::cout << str << std::endl;
}
};
int main ()
{
foo f({"one", "two", "three"});
}