1

如果 T 不是某种类型,是否可以禁用Foo()派生类中的覆盖(通过或一些增强魔法),而不必为 编写模板特化?std::enable_ifclass Derived

加分项:如果 T 没有定义某种方法,是否可以禁用覆盖?

这是我的SSCCE:

#include <iostream>
#include <string>

class Base
{
public:
    virtual std::string Foo()
    {
        return "Base";
    }
};

template <typename T>
class Derived : public Base
{
public:
    virtual std::string Foo() override
    {
        return "Derived";
    }
};

int main()
{
    Derived<int> testInt;
    std::cout << testInt.Foo() << std::endl;

    Derived<float> testFloat;
    std::cout << testFloat.Foo() << std::endl;//I would like this to print 'Base'
}

更新:

感谢您提供出色的解决方案,但我无法使它们适应我的真实代码。以下示例应该更好地了解我要实现的目标:

#include <iostream>
#include <string>

class Object
{
public:
    void Test()
    {
        std::cout << "Test" << std::endl;
    }
};

class EmptyObject
{
};

class Base
{
public:
    virtual std::string Foo()
    {
        return "Base";
    }
};

template <typename T>
class Derived : public Base
{
public:
    virtual std::string Foo() override
    {
        m_object.Test();
        return "Derived";
    }

private:
    T m_object;
};

int main()
{
    Derived<Object> testObject;
    std::cout << testObject.Foo() << std::endl;

    Derived<EmptyObject> testEmpty;
    std::cout << testEmpty.Foo() << std::endl;
}
4

4 回答 4

1

如果你需要在编译时限制某种类型,你可以std::enable_ifstd::is_same

typename std::enable_if<std::is_same<T, float>::value, std::string>::type 
virtual Foo() override
{
    return "Derived";
}

Base或者,如果模板类型不是您要查找的类型,您可以轻松地将调用重定向到该方法,仍然使用std::is_same

virtual std::string Foo() override
{
    return std::is_same<T, float>::value ? Base::Foo() : "Derived";
}

至于奖金,您可以从这个SO 答案中获得特征,在此处改编decltype为一种方法bar()

template <typename T>
class has_bar
{
    typedef char one;
    typedef long two;

    template <typename C> static one test(decltype(&C::bar) ) ;
    template <typename C> static two test(...);

public:
    enum { value = sizeof(test<T>(0)) == sizeof(char) };
};

限制是您不能对参数或返回类型施加约束。

virtual std::string Foo() override
{
    return has_bar<T>::value ? "Derived" : Base::Foo() ;
}

笔记:

您也可以has_bar与我的第一个示例中的 with 一起使用enable_if,以在编译时禁用它。

于 2014-06-16T17:57:55.080 回答
1

Instead of template specialize the class, you may template specialize the method directly: (https://ideone.com/gYwt5r)

template<> std::string Derived<float>::Foo() { return Base::Foo(); }

And I only see template specialization of a class to disable future override depending of T by adding final to the virtual method.

于 2014-06-16T17:23:23.010 回答
1

我会通过创建两个Derived::Foo可以根据是否有条件委托给的函数来做到这一点T = float。一个将包含真正的Derived::Foo实现,而另一个将调用Base::Foo.

template <typename T>
class Derived : public Base
{
public:
    virtual std::string Foo() override
    {
        return do_Foo(std::is_same<T, float>{});
    }

private:
    std::string do_Foo(std::false_type)
    {
        return "Derived";
    }
    std::string do_Foo(std::true_type)
    {
        return Base::Foo();
    }
};

现场演示


看来您实际上想要做的是仅在定义某个成员函数时才调用Derived<T>::Foo()实现,否则应该调用。这可以使用表达式 SFINAE 来完成。TBase::Foo()

template <typename T>
class Derived : public Base
{
public:
    std::string Foo() override
    {
        return do_Foo(true);
    }
private:
    template<typename U = T>
    auto do_Foo(bool)
        -> decltype(std::declval<U>().test(), void(), std::string())
    {
        return "Derived";
    }
    std::string do_Foo(int)
    {
        return Base::Foo();
    }
};

现场演示

在上面的代码中,如果类型T没有定义名为 的成员函数test(),则do_Foo(bool)成员函数模板将不可行。另一方面,如果T::test()确实存在,do_Foo(bool)则将选择 then ,因为传递给do_Fooby的布尔值Foo使其比do_Foo(int).

decltype可以在此处找到有关尾随返回类型中的表达式中发生的事情的详细说明。

于 2014-06-16T17:28:15.153 回答
1

您可以在层次结构中添加一个中间类:

class Base
{
public:
    virtual std::string Foo()
    {
        return "Base";
    }
};

template <typename T>
class Intermediate : public Base
{
    // common operations with m_object

protected: // not private!
    T m_object;
};

template <typename T, typename = bool>
class Derived : public Intermediate<T> {};

template <typename T>
class Derived<T, decltype(std::declval<T>().Test(), void(), true)>
    : public Intermediate<T>
{
public:
    virtual std::string Foo() override
    {
        this->m_object.Test(); // this-> is necessary here!
        return "Derived";
    }
};

完整的示例使用clang 3.4g++ 4.8.2成功编译。

于 2014-06-16T19:59:44.243 回答