C ++模糊模板重载

时间:2019-02-13 18:08:17

标签: c++ templates template-specialization

我正在尝试使用模板专门化以根据模板变量的值返回不同的类型。

我已经从尝试在运行时分支而不是使用typeof(),非专业模板以及使用std::enable_if_t<>进行编译。我认为这可能是由于对模板功能如何解决缺乏了解。

class Test
{
public:
    template <typename T>
    T request()
    {
        T ret = getVal<T>();
        return ret;
    }

private:
    float foo = 2.f;
    int bar = 1;

    template <typename T>
    typename std::enable_if<std::is_same<T, float>::value, bool>::type
    getVal() { return foo; }

    template <typename T>
    typename std::enable_if<std::is_same<T, int>::value, bool>::type
    getVal() { return bar; }

    template<typename T>
    T getVal()
    {
        std::cout << "T is type " << typeid(T).name() << std::endl;
        throw std::bad_typeid();
    }
};

int main()
{
    Test t;
    int i;
    float f;
    i = t.template request<int>();
    f = t.template request<float>();
}

我希望这可以解决三个不同的功能,但是我不确定是否是这样:

T Test::getVal()

int Test::getVal()

float Test::getVal()

任何帮助将不胜感激。

2 个答案:

答案 0 :(得分:0)

您的问题是,当SFINAEd成功通过template<typename T> T getVal()时,通话会变得不明确。

一种解决方案是用补码条件限制该条件...

但是标签分发是解决问题的一种简单的替代方法:

template <typename> struct Tag{};

class Test
{
public:
    template <typename T>
    T request() const
    {
        return getVal(Tag<T>{});
    }

private:
    float foo = 2.f;
    int bar = 1;

    float getVal(Tag<float>) const { return foo; }
    int getVal(Tag<int>) const { return bar; }

    template<typename T> void getVal(Tag<T>) = delete;
};

答案 1 :(得分:0)

您可以通过专门设置getVal()来轻松完成此操作,尽管您可能已经将问题简化了

class Test {
public:
    template <typename T>
    T request() {
        T ret = getVal<T>();
        return ret;
    }

private:
    float foo = 2.f;
    int bar = 1;

    template<typename T>
    T getVal() {
        std::cout << "T is type " << typeid(T).name() << std::endl;
        throw std::bad_typeid();
    }
};

// add specializations
template<>
float Test::getVal<float>() { return foo; }

template <>
int Test::getVal<int>() { return bar; }

int main() {
    Test t;
    int i = t.request<int>(); // don't need template keyword here
    float f = t.request<float>();
}

如果您能够使用c ++ 17,则使用if constexpr和单个getVal会更简单

template<typename T>
auto getVal() {
  if constexpr (std::is_same_v<int, T>) {
    return foo;
  } else if constexpr (std::is_same_v<float, T>) {
    return bar;
  } else {
    std::cout << "T is type " << typeid(T).name() << std::endl;
    throw std::bad_typeid();
  }
}