add function member to a template class conditionally [duplicate]

喜欢而已 提交于 2020-05-14 08:48:07

问题


I have a class template defined as follow

template<typename T>
class A
{
  T t_;
  // void f();
};

My question is how to add the f() method only if the type T is integer without compilation error.

int main()
{
  A<int> a; // OK
  A<string> b; // OK
}

Example :

#include <type_traits>
#include <new>
#include <iostream>
#include <string>



template <typename T>
struct Foo
{
    T t;
    template <typename..., typename U = T>
    std::enable_if_t<std::is_same_v<T, int>> say_hello() { std::cout << "Hello"; }
};


int main()
{
    Foo<int>();
    Foo<double>();
}
Error   C2938   'std::enable_if_t<false,void>' : Failed to specialize alias template

Thank you.


回答1:


You can enable specific functions using type_traits and SFINAE:

#include <iostream>
#include <string>
#include <type_traits>

template<typename T>
class A
{
public:
    template<typename U = T, std::enable_if_t<std::is_integral_v<U>, int> = 0>
    void f() {
        std::cout << "int " << t_ << '\n';
    }
private:
    T t_;
};


int main() {
    A<int> a;
    a.f();

    A<std::string> s;
    // s.f(); //  error: no member named 'f' in 'A<std::__cxx11::basic_string<char> >'
}

If you have many integer specific functions you can put them in a class of its own and inherit that class only if T is integral.

#include <iostream>
#include <string>
#include <type_traits>

template<typename Atype>
class int_functions {
public:
    Atype* This() { return static_cast<Atype*>(this); }

    void f() {
        std::cout << "int " << This()->t_ << '\n';
    }
};

template<typename Atype>
class non_int_functions {
};

template<typename T>
class A : public std::conditional_t<std::is_integral_v<T>, int_functions<A<T>>,
                                                           non_int_functions<A<T>>>
{
    friend std::conditional_t<std::is_integral_v<T>, int_functions<A<T>>,
                                                     non_int_functions<A<T>>>;
public:
private:
    T t_;
};



回答2:


You can use partial specialization, as follows

template<typename T>
class A
{
  T t_;
  // void f()
};

template<>
class A<int>
{
  int t_;
   void f(){}
};

--Edit--

You can put your original class as a Base<T> and the make a new class A<T> inheriting from Base, then partially specialized A<int> and add your function as follows

#include<string>
template<typename T>
struct Base
{
    T t_{};
};

template<typename T>
struct A:public Base<T>
{
};

template<>
struct A<int>:public Base<int>
{
    void f(){
        std::cout<<"in A<int>\n";
    }
};

int main()
{
    A<int> a; // OK
    a.f();
    A<std::string> b; // OK
    //b.f();     //compilation error
}


来源:https://stackoverflow.com/questions/60768553/add-function-member-to-a-template-class-conditionally

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!