我想知道C++ 0x是否提供了任何内置功能来检查可变参数模板的参数包是否包含特定类型.今天,如果你使用boost :: mpl :: vector作为variadic模板的替代品,可以用boost ::: mpl :: contains来实现这个目的.但是,它有严重的编译时间开销.我想,C++ 0x对std :: is_same有编译器级支持.所以我在想是否在编译器中也支持如下的泛化.
template <typename... Args, typename What>
struct is_present
{
enum { value = (What in Args...)? 1 : 0 };
};
Run Code Online (Sandbox Code Playgroud) 是否可以通过重载参数的运算符逗号来为函数构造可变参数?我想看一个如何做的例子......,也许是这样的:
template <typename T> class ArgList {
public:
ArgList(const T& a);
ArgList<T>& operator,(const T& a,const T& b);
}
//declaration
void myFunction(ArgList<int> list);
//in use:
myFunction(1,2,3,4);
//or maybe:
myFunction(ArgList<int>(1),2,3,4);
Run Code Online (Sandbox Code Playgroud) 是否有一个宏告诉我我的编译器是否支持可变参数模板?
#ifdef VARIADIC_TEMPLATES_AVAILABLE
template<typename... Args> void coolstuff(Args&&... args);
#else
???
#endif
Run Code Online (Sandbox Code Playgroud)
如果它们不受支持,我想我会用一堆重载来模拟它们.有更好的想法吗?也许有预处理器库可以轻松完成工作?
我有两个函数a()和b(),两者都是可变函数,让我说当我调用函数a()时这样:
a(arg0, arg1, arg2, arg3, ...., argn);
Run Code Online (Sandbox Code Playgroud)
然后函数b()也将在a()中调用,但是在()的参数列表中没有第一个参数"arg0":
b(arg1, arg2, arg3, ...., argn);
Run Code Online (Sandbox Code Playgroud)
有什么办法吗?
我正在为C中的列表实现简单的库,我在编写find函数时遇到了问题.
我希望我的函数接受任何类型的参数来查找,和:
find(my_list, 3)和find(my_list, my_int_var_to_find).
我已经掌握了列表元素类型的信息.
现在我已经找到了几种解决这个问题的方法:
带有不同类型后缀的不同功能:int findi(void* list, int i),int findd(void* list, double d)- 但我不喜欢这种方法,对我来说似乎是冗余,而且API令人困惑.
使用联盟:
typedef union {
int i;
double d;
char c;
...
} any_type;
Run Code Online (Sandbox Code Playgroud)
但是这样我强迫用户既知道了any_typeunion,又在调用之前创建它find.我想避免这种情况.
使用可变函数:int find(void* list, ...).我喜欢这种方法.但是,我担心没有对参数数量的限制.用户可以自由写,int x = find(list, 1, 2.0, 'c')虽然我不知道它应该是什么意思.
我也看到了这个问题的答案:C:为一个函数参数发送不同的结构,但它无关紧要,因为我想接受非指针参数.
处理此功能的正确方法是什么?
我想写一个lambda,它通过通用引用获取任意数量的参数,并完全忽略它们.显而易见的方法是使用可变参数通用参数包的语法并省略参数名称:
auto my_lambda = [](auto&&...) { return 42; };
Run Code Online (Sandbox Code Playgroud)
这工作正常(使用gcc 4.9.2),直到我尝试传递一个非平凡的可复制对象:
struct S { S() {} S(S const&) {} };
my_lambda("meow", 42, S{});
^ error: cannot pass objects of non-trivially-copyable type 'struct S' through '...'
Run Code Online (Sandbox Code Playgroud)
这是怎么回事?我的代码是不正确的,还是gcc中的错误?
在任何一种情况下,最好的解决方法是什么?我发现命名参数有效,但后来我遇到了一个未使用的参数警告:
auto my_lambda = [](auto&&... unused) { return 42; };
^ error: unused parameter 'unused#0' [-Werror=unused-parameter]
^ error: unused parameter 'unused#1' [-Werror=unused-parameter]
^ error: unused parameter 'unused#2' [-Werror=unused-parameter]
Run Code Online (Sandbox Code Playgroud)
如何在模板参数包上抑制未使用的参数警告?
与这个问题联合起来.我无法为以下看似基本的问题提出一个良好的类型安全解决方案.我有一个类music_playlist,它有一个应该播放的歌曲列表.看起来非常简单,只需创建队列中所有歌曲的std :: list,并将其提供给用户.然而,出于必要,音频解码和音频呈现发生在不同的线程上.因此列表需要受互斥保护.很多时候,使用我的库的其他程序员忘记了互斥锁.这显然导致了"奇怪"的问题.
所以起初我只是为班级编写了setter.
struct music{};
class music_playlist{
private:
std::list<music> playlist;
public:
void add_song(music &song){playlist.push_back(song);}
void clear(){playlist.clear();}
void set_list(std::list<music> &songs){playlist.assign(songs.begin(),songs.end());}
//etc
};
Run Code Online (Sandbox Code Playgroud)
这导致用户代码如下...
music song1;
music song2;
music song3;
music song4;
music song5;
music song6;
music_playlist playlist1;
playlist1.add_song(song1);
playlist1.add_song(song2);
playlist1.add_song(song3);
playlist1.add_song(song4);
playlist1.add_song(song5);
playlist1.add_song(song6);
//or
music_playlist playlist2;
std::list<music> songs;
songs.push_back(song1);
songs.push_back(song2);
songs.push_back(song3);
songs.push_back(song3);
songs.push_back(song5);
songs.push_back(song6);
playlist2.set_list(songs);
Run Code Online (Sandbox Code Playgroud)
虽然这是有效的,但非常明确.输入是非常繁琐的,并且由于实际工作周围的所有残余而容易出错.为了证明这一点,我实际上故意在上面的代码中添加了一个错误,这样的东西很容易制作,并且可能不会触及代码评论,而song4永远不会在播放列表2中播放.
从那里我开始研究可变函数.
struct music{};
class music_playlist{
private:
std::list<music> playlist;
public:
void set_listA(music *first,...){
//Not guaranteed to work, but usually does... bleh
va_list Arguments; …Run Code Online (Sandbox Code Playgroud) 在这段代码中,我试图Test从 usingArg到 using进行概括Args...。问题是默认的模板参数。我在下面编译的内容,除非我取消注释 main() 中的注释行:
#include <iostream>
#include <type_traits>
struct A {
void foo(int) const {}
void foo(int, bool, char) const {}
};
template <typename...> struct voider { using type = void; };
template <typename... Ts>
using void_t = typename voider<Ts...>::type;
template <typename T, typename Arg, typename = void_t<T>>
struct Test : std::false_type {};
template <typename T, typename Arg>
struct Test<T, Arg, void_t<decltype(std::declval<T&>().foo(std::declval<Arg>()))>> :
std::true_type {};
// Trying to generalize Test with Args... instead …Run Code Online (Sandbox Code Playgroud) 我的 C 代码中内置了一个标准的日志 API,这是一个很好的简单的logF(const char *pFormat, ...)东西,到目前为止,它一直被映射到vprintf(),即:
void logF(const char *pFormat, ...)
{
va_list args;
va_start(args, pFormat);
vprintf(pFormat, args);
va_end(args);
}
Run Code Online (Sandbox Code Playgroud)
此 API 上方的 C 代码必须适用于多个嵌入式平台。我刚刚到达了一个平台 (Nordic NRF52840),在该平台中,我必须使用的底层日志记录接口显示为表单的可变参数宏NRF_LOG_INFO(...)。
问题:如何正确传递fn(const char *pFormat, ...)到BLAH(...)宏?我的脑袋疼....
这是 GCC 4.9.3,不过如果有一个对 C 编译器版本相对宽松的解决方案会很好。
编辑 1:注意到我可以将我的logF()函数重新定义为可变参数宏并将其映射到那里,问题是我将拥有一个特定于平台的头文件而不是通用头文件,我必须将它移到平台中代码,每个都有一个。并非不可能,但更混乱。
编辑 2:我被问到如何NRF_LOG_INFO()扩展的线索。这是预处理器的相关输出:
#define NRF_LOG_INFO(...) NRF_LOG_INTERNAL_INFO( __VA_ARGS__)
#define NRF_LOG_INTERNAL_INFO(...) NRF_LOG_INTERNAL_MODULE(NRF_LOG_SEVERITY_INFO, NRF_LOG_SEVERITY_INFO, __VA_ARGS__)
#define NRF_LOG_INTERNAL_MODULE(level,level_id,...) if (NRF_LOG_ENABLED && (NRF_LOG_LEVEL >= level) && (level <= NRF_LOG_DEFAULT_LEVEL)) { if (NRF_LOG_FILTER >= …Run Code Online (Sandbox Code Playgroud) 更新:编辑以修复工作示例中的编译。
我想做类似下面的事情,以便该函数可以接受枚举类实例的列表或保存它们的结构,但是 的定义auto myFunc2<EList<Types...>>失败expected a constant not E::A
#include <cstdint>
#include <iostream>
enum class E {A = 0, B=1};
template<E... Types> struct tl2 {};
using my_list_2 = tl2<E::A>;
template <E ... Types>
auto myFunc2 = [] {
std::cout << "Size: " << sizeof...(Types) << std::endl;
};
template <template<E...> typename EList, E... Types>
auto myFunc2<EList<Types...>> = [] {
std::cout << "Size: " << sizeof...(Types) << std::endl;
};
int main() {
myFunc2<E::A, E::B>(); // This call prints size of …Run Code Online (Sandbox Code Playgroud)