如何使用C TMP实现多nitValue类
How to implement MultiUnitValue class using C++ TMP
我在vc 上写了这一类,这显然是不合规的(TBH似乎很奇怪,标准不允许它)
- 如何将其转换为标准C 11?
代码:
#include <functional>
template <typename T, typename U, typename T_to_U >
class MultiUnitValue //Multi for now == 2 :)
{
const T t;
T_to_U conversion_function;
public:
MultiUnitValue() : t(0)
{}
MultiUnitValue(T t_): t(t_)
{}
template<typename V>
V in() const
{
BOOST_STATIC_ASSERT(0);
// "you are trying to call in with type(unit) not supported"
}
template<>
T in<T>() const
{
return t;
}
template<>
U in<U>() const
{
return conversion_function(t);
}
};
用法:
auto f = [](int i){return i*2.54;};
MultiUnitValue<int, float,decltype(f)> muv(10);
auto rv = muv.in<float>();
- 我将boostrongtatic_assert放置以防止使用不正确的用法,
但是看起来MSVC如果不使用(如我所期望的),MSVC不会实例化,但是在试图将其移植到G 4.7时,即使模板未实例化,也正在触发它?用static_assert替换它不起作用...
有什么方法可以解决这个问题?
您的解决方案不是"标准符合标准的",因为成员函数不能在类模板中专门化。这是因为一般规则认为函数不能部分专业化 - 因此,即使不是完全专业的类,也可以对成员函数模板进行"完整"专业化。
我的解决方案:
C 11版本
您的版本示例,我相信这就是您想要的:
int main(){
auto f1 = [](int i){return i*2.54;};
auto f2 = [](int i){ std::stringstream ss; ss << i; return ss.str(); };
MultiUnitValue<int, float, std::string> vv(1, f1, f2);
std::cout << vv.in<int>() << "n";
std::cout << vv.in<float>() << "n";
std::cout << vv.in<std::string>() << "n";
// std::cout << vv.in<long>() << "n"; // error to compile
}
首先 - 您需要特殊的转换基类,对于单个转换,您将在下一个代码片段中看到,通过基类函数调用转换是"非指定"转换的原因,例如long
不编译。
template <class T, class U>
class Conversion {
public:
Conversion(const std::function<U(const T&)>& f) : f(f) {}
U convert (const T& v) const { return f(v); }
private:
std::function<U(const T&)> f;
};
template <class T>
class Conversion<T,T> {
public:
T convert (const T& v) const { return v; }
};
和您的班级使用variadic模板:
template <class T, class... V> // V... means all desired conversions
class MultiUnitValue : private Conversion<T,T>, private Conversion<T,V>... {
// allowed conversion: ^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
public:
MultiUnitValue(T v, const std::function<V(const T&)>&... f) : Conversion<T,V>(f)..., v(v) {}
template <class U>
U in() const
{
// this static assert is not needed - but just to show the message
static_assert(std::is_base_of<Conversion<T,U>, MultiUnitValue<T,V...>>::value,
"Not allowed conversion");
// static_assert is not needed
// since if you MultiUnitValue does not derive from Conversion<T,U>
// - then this call will not compile too
return this->Conversion<T,U>::convert(v);
}
private:
T v;
};
lvs示例:http://liveworkspace.org/code/05b6ada146cc8f05d027a55536859a087
没有变化模板的版本:
我还准备了没有变异模板的解决方案,因为VC 仍然不支持它们。
第二:转换和覆盖限制现在应在您的T_TO_U类型中。
使用此方法使用将在与C 11版本的比较中有些不便:
int main(){
auto f1 = [](int i){return i*2.54;};
auto f2 = [](int i){ std::stringstream ss; ss << i; return ss.str(); };
// next 2 lines differ from C++11 version
typedef ConvertFunctions2<int, float, std::string> CF_f1_f2;
MultiUnitValue<int, CF_f1_f2> vv(1, CF_f1_f2(f1, f2));
std::cout << vv.in<int>() << "n";
std::cout << vv.in<float>() << "n";
std::cout << vv.in<std::string>() << "n";
// std::cout << vv.in<long>() << "n"; // error to compile
}
MultiUnitValue
比您的示例更简单,即使从我的C 11版本中,class CF
也会更复杂:
template <class T, class CF>
class MultiUnitValue {
public:
MultiUnitValue(T v, const CF& cf) : v(v), cf(cf) {}
template <class U>
U in() const
{
return cf.Conversion<T,U>::convert(v);
}
private:
T v;
CF cf;
};
简单的"助手"转换类将与C 11版中的版本相同:
template <class T, class U>
class Conversion {
...
};
template <class T>
class Conversion<T,T> {
...
};
和VC 中的variadic模板替代方案(以及C 03的过去):
template <class T>
class ConvertFunctions0 : public Conversion<T,T> {};
template <class T, class V1>
class ConvertFunctions1 : public Conversion<T,T>, public Conversion<T,V1> {
public:
ConvertFunctions1(std::function<V1(const T&)> f1) : Conversion<T,V1>(f1) {}
};
template <class T, class V1, class V2>
class ConvertFunctions2 : public Conversion<T,T>, public Conversion<T,V1>, public Conversion<T,V2> {
public:
ConvertFunctions2(std::function<V1(const T&)> f1, std::function<V2(const T&)> f2)
: Conversion<T,V1>(f1), Conversion<T,V2>(f2)
{}
};
您可以看到 - 添加ConvertFunctions3
,ConvertFunctions4
并不是那么大麻烦...
IDEONE的完整示例
第一个问题是您无法在类中专业化成员函数模板,并且您无法在(模板)类中专业化它们,因为它们将成为部分函数专业。解决此问题的最简单方法是使用私人成员功能超载:
private:
T in(T *) const { return t; }
U in(U *) const { return conversion_function(t); }
template<typename V> V in(V *) const {
static_assert((V *)0, "you are trying to call in with type(unit) not supported");
}
public:
template<typename V> V in() const { return in((V *)0); }
这也演示了如何通过static_assert
始终触发解决问题;您需要使其断言表达式取决于模板参数。
下一个问题是您的模板不会与lambda类型模板参数实例化,因为lambdas(甚至是无绑定的lambdas)都不是默认的构造。您可以通过返回传统函数(带有operator()
的struct
)或将lambda类型转换为调用lambda的默认构造类型来解决此问题。
一种策略是在打电话时间接一个空隙指针,因为无绑定的lambdas不应该关心他们的this
指针是什么:
template<typename L> struct default_constructible_lambda {
template<typename... Args> auto operator()(Args &&...args) const
-> decltype(std::declval<L>()(std::forward<Args>(args)...)) {
return (*(L *)(0))(std::forward<Args>(args)...); }
};
MultiUnitValue<int, float, default_constructible_lambda<decltype(f)>> muv(10);
这仍然是未定义的行为;这与将lambda的功能指针存储在闭合类型中的标准是一致的,在这种情况下,这将导致通过void Pointer致电。
- 如果没有malloc,链表实现将失败
- 如何在c++中实现处理器调度模拟器
- 如何在c++中使用引用实现类似python的行为
- 实现无开销push_back的最佳方法是什么
- 使用简单类型列表实现的指数编译时间.为什么
- 如何在BST的这个简单递归实现中消除警告
- 实现一个在集合上迭代的模板函数
- 我应该实现右值推送功能吗?我应该使用std::move吗
- 如何正确实现和访问运算符的各种自定义枚举器
- C++Union/Struct位域的实现和可移植性
- 这个极客对极客的trie实现是否存在内存泄漏问题
- 在c++中实现LinkedList时,应出现未处理的错误
- 为左值和右值的包装器实现C++范围
- 使用模板进行堆栈实现; "name followed by :: must be a class or namespace"
- 使用GSoap实现ONVIF
- 在用于格式4的arm模拟器中实现功能时的一个问题
- 用于AVX的ln(x)的实现,m256
- 用常见虚拟函数实现的任意组合来实现派生类的正确方法是什么
- 在C++中,如何在类和函数(可能是模板化的)的头中编写完整的实现
- 如何使用C TMP实现多nitValue类