【发布时间】:2016-01-05 19:42:13
【问题描述】:
将模板类型推导与 C++14 std::get 与类型索引结合使用时出现错误。代码可能看起来有点复杂,但我已尝试将其缩减为所发生事情的基本情况。它实际上只是一个观察者模式......结构'A'允许根据消息类型(M1,M2,......)设置观察者。请注意,为了简单起见,每种消息类型只有一个观察者。
现在诀窍(以及失败的部分)是使用 C++14 的 std::get,它允许您使用实际类型索引到唯一类型的元组。这是一个简单的例子来说明我的意思:
void sample()
{
std::tuple<int, float> myTuple;
std::get<float>(myTuple) = 3.141f; // C++14 allows this
std::get<1>(myTuple) = 3.141f; // C++11 way to do it, using index
}
考虑到这一点,这是我的程序(与上面的代码分开)因为 C++14 元组类型索引在推断类型上失败而无法编译:
#include <cxxabi.h>
#include <stdlib.h>
#include <functional>
#include <vector>
#include <tuple>
#include <typeinfo>
#include <iostream>
#include <string>
// ===================================
// A quick'n'dirty way to print types (nonportable)
// And yes, I know this code could be improved :)
inline
std::string demangle(char const *mangled)
{
char *output = (char *)malloc(16384);
size_t length = 16384;
int status;
__cxxabiv1::__cxa_demangle(mangled, output, &length, &status);
std::string s(output, length);
free(output);
return s;
}
#define DEMANGLE(T) demangle(typeid(T).name())
// ===================================
struct A
{
struct M1
{};
struct M2
{};
using Tuple = std::tuple<
std::function<void(M1 const &)>
,std::function<void(M2 const &)>
>;
template<typename T>
void setObserver(T func)
{
// This works fine
std::cout << DEMANGLE(T) << std::endl;
// ************************************************
// The line below does not compile (std::get fails)
//
// Note the type of T prints out as:
// std::_Bind<std::_Mem_fn<void (B::*)(A::M1 const&)> (B*, std::_Placeholder<1>)>
//
// Rather than the (desired):
// std::function<void (A::M1 const&)>(A::M1 const&)> (B*, std::_Placeholder<1>)>
//
// ************************************************
std::get<T>(tuple_) = func; // C++14 only
}
private:
Tuple tuple_;
};
// ===================================
struct B
{
void func(A::M1 const &)
{}
};
// ===================================
int main()
{
A *a = new A;
B *b = new B;
using namespace std::placeholders;
a->addObserver(std::bind(&B::func, b, _1));
return 0;
}
更新:
建议的解决方案确实解决了从 std::bind(...) 转换为 std::function(...) 的问题,但它要求我为我的每种类型都有一个单独的 setObserver() 函数M1,M2,...
如何模板化 setObserver() 来解决这个问题?
【问题讨论】:
标签: c++ templates tuples c++14 stdbind