Select constructor through SFINAE in template arguments

主宰稳场 提交于 2019-12-10 20:26:30

问题


I'm trying to select a constructor through SFINAE as following:

template<typename T>
class MyClass
{
public:
    template<typename C, typename = std::enable_if_t<std::is_class<C>::value>>
    MyClass(C) { }

    template<typename C, typename = std::enable_if_t<std::is_pointer<C>::value>>
    MyClass(C) { }
};

but the compiler complains with following error:

error C2535: 'MyClass::MyClass(C)': member function already defined or declared

without even instantiating the constructor.

I worked out a working but ugly solution which i don't want to use because of the extra unused parameter:

template<typename T>
class MyWorkingClass
{
public:
    template<typename C>
    MyWorkingClass(C, std::enable_if_t<std::is_class<C>::value>* = nullptr) { }

    template<typename C>
    MyWorkingClass(C, std::enable_if_t<std::is_pointer<C>::value>* = nullptr) { }
};

A short usage example is given here:

void* ptr = nullptr;
MyClass<int> mc1(ptr);

std::vector<int> vec;
MyClass<int> mc2(vec);

// Shall raise an error
// MyClass<int> mc2(0);

The traits std::is_pointer and std::is_class are just an example, the original traits are more complicated.

Is there a way to select the constructor through SFINAE without adding another parameter to the constructor (maybe very close to the first appproach)?


回答1:


The problem is that the default values of arguments are not part of the template method signature. So you have two template<class C,class>ctor(c) identical ctors.

template<class T>
struct MyClass {
  template<class C,
    std::enable_if_t<std::is_class<C>{}>* =nullptr
  >
  MyClass(C) { }
  template<class C,
    std::enable_if_t<std::is_pointer<C>{}>* =nullptr
  >
  MyClass(C) { }
};

here we use template value arguments of dependant type. They never conflict, as the type of the pointer template argument is dependant on the type argument.




回答2:


Add one more (dummy) type template parameter:

template <typename C
        , typename = std::enable_if_t<std::is_class<C>::value>>
MyClass(C) { }

template <typename C
        , typename = std::enable_if_t<std::is_pointer<C>::value>
        , typename = void>
//        ~~~~~~~~~~~~~~^
MyClass(C) { }

DEMO




回答3:


This may be simplier:

template<typename T>
class MyClass {
public:
    template<typename C, typename = std::enable_if_t<std::is_class<C>::value>>
    MyClass(C) { }

    template<typename C>
    MyClass(C*) { }
};

Not all of them need to be done by std::enable_if_t.



来源:https://stackoverflow.com/questions/32167213/select-constructor-through-sfinae-in-template-arguments

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