gpt4 book ai didi

c++ - 如何使用 C++ TMP 实现 MultiUnitValue 类

转载 作者:塔克拉玛干 更新时间:2023-11-02 23:32:04 25 4
gpt4 key购买 nike

我用 VC++ 编写了这个类,这显然不符合标准(TBH 似乎很奇怪,标准不允许)

  1. 如何将其转换为标准 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>();
  1. 我放置了 BOOST_STATIC_ASSERT 以防止不正确的使用,
    但是看起来 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; }
};

你的类(class)使用可变参数模板:

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/05b6ada146cc8f05d027a5536859a087

没有可变参数模板的版本:

我还准备了没有可变参数模板的解决方案,因为 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++ 中的可变参数模板替代方案(以及过去的 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)
{}
};

如您所见 - 添加 ConvertFunctions3ConvertFunctions4 并不是什么大麻烦...

完整示例位于 ideone

关于c++ - 如何使用 C++ TMP 实现 MultiUnitValue 类,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13067712/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com