如何创建一个将Class <t>转换为Class <u>的函数,其中T和U是任意数字类型?

时间:2015-09-28 17:35:54

标签: c++ templates c++11

我正在使用SFML,我想做以下事情:

sf::Texture myTexture;
myTexture.loadFromFile("texture.png");

sf::Sprite mySprite(myTexture);
mySprite.setOrigin(myTexture.getSize() / 2.f); // <~-- error

问题在于sf::Texture::getSize()会返回sf::Vector2< unsigned >,而sf::Transformable::setOrigin()则需要sf::Vector2< } float >,并且他们无法相互转换。

我考虑创建一个接受任何sf::Vector2<T>并返回等效sf::Vector<U>的函数,其中TU都是任意数字类型,所以我可以重写最后一行代码为:

// converting from 'unsigned' to 'float'
mySprite.setOrigin(toVector2<unsigned, float>(myTexture.getSize()) / 2.f);

到目前为止我所拥有的是以下内容,但它不起作用。

// Util.h
namespace smi
{
    template <typename FROM, typename TO>
    sf::Vector2<TO> toVector2(const sf::Vector2<FROM> &other)
    {
        return sf::Vector2<TO>(
            static_cast<TO>(other.x),
            static_cast<TO>(other.y));
    }
}

// then ...
mySprite.setOrigin(toVector2<unsigned, float>(myTexture.getSize()) / 2.f);
// ^ no instance of function template "toVector2" matches the argument list

这是显示错误的图片:

Error message: no instance of function template "toVector2" matches the argument list

我怎样才能实现这种通用转换?

2 个答案:

答案 0 :(得分:3)

通常,您不能对任意类型执行此操作。类模板的两个不同特化之间不一定有任何关系,也没有从一个模板转换到另一个模板的通用方法。

对于特定情况,您通常可以执行以下操作:

template <typename To, typename From>
  Thing<To> convert(const Thing<From>& from)
  {
    return Thing<To>( /* internal value(s) of from */ );
  }

即。从源对象中保存的值构造一个新对象。但要做到这一点,你需要知道类型的API,以便你可以获取值并调用适当的构造函数,例如。

template <typename To, typename From>
  std::complex<To> convert_complex(const std::complex<From>& from)
  {
    return std::complex<To>( from.real(), from.imag() );
  }

或:

template <typename To, typename From>
  std::vector<To> convert_vector(const std::vector<From>& from)
  {
    return std::vector<To>( from.begin(), from.end() );
  }

或:

template <typename To, typename From>
  std::shared_ptr<To> convert_shared_ptr(const std::shared_ptr<From>& from)
  {
    return std::dynamic_pointer_cast<To>(from);
  }

但是没有办法完全一般地做到这一点,因为每个类型都有不同的API来获取其内部值(如果它甚至可能)以及构建新对象。

你的toVector2函数看起来应该可以正常工作,因为它确实如此。正如Pete所指出的那样,错误显示你没有定义你的toVector2函数,如你的问题中所示:你把参数反过来了!

N.B。您可以重新排序模板参数,以便您可以使用模板参数推导来简化转换功能:

template <typename To, typename From>
  sf::Vector2<To> toVector2(const sf::Vector2<From>& other)
  {
    return ...
  }

现在您可以致电toVector2<float>(myTexture.getSize())From参数将推断为unsigned

因为这似乎就是你如何定义真实函数的方法,只需将代码更改为toVector2<float>(myTexture.getSize())它就可以了。

答案 1 :(得分:0)

这是我提出的:

template<typename From, typename To>
std::vector<To> transform_vector(const std::vector<From>& input)
{
    std::vector<To> output;
    for (const auto& i : input)
        output.emplace_back(static_cast<To>(i));
    return std::move(output);
}

int main()
{
    std::vector<double> test{ 1.5, 3.8, 2 };
    std::vector<int> conv = transform_vector<double, int>(test);

    for (auto i : conv)
        std::cout << i << " ";
    std::cout << std::endl;
}

不确定为什么编译器无法推断出类型。