Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用不同的启用条件选择成员函数_C++_Templates_C++11_Sfinae_Specialization - Fatal编程技术网

C++ 使用不同的启用条件选择成员函数

C++ 使用不同的启用条件选择成员函数,c++,templates,c++11,sfinae,specialization,C++,Templates,C++11,Sfinae,Specialization,我试图根据类模板参数确定调用成员函数的哪个版本。我试过这个: #include <iostream> #include <type_traits> template<typename T> struct Point { void MyFunction(typename std::enable_if<std::is_same<T, int>::value, T >::type* = 0) { std::cout <

我试图根据类模板参数确定调用成员函数的哪个版本。我试过这个:

#include <iostream>
#include <type_traits>

template<typename T>
struct Point
{
  void MyFunction(typename std::enable_if<std::is_same<T, int>::value, T >::type* = 0)
  {
    std::cout << "T is int." << std::endl;
  }

  void MyFunction(typename std::enable_if<!std::is_same<T, int>::value, float >::type* = 0)
  {
    std::cout << "T is not int." << std::endl;
  }
};

int main()
{
  Point<int> intPoint;
  intPoint.MyFunction();

  Point<float> floatPoint;
  floatPoint.MyFunction();
}
#包括
#包括
模板
结构点
{
void MyFunction(typename std::enable_if::type*=0)
{
std::cout intPoint;
intPoint.MyFunction();
点浮点数;
floatPoint.MyFunction();
}

我认为这是在说“如果T是int,使用第一个MyFunction,如果T不是int,使用第二个MyFunction,但是我得到的编译器错误是”错误:在'struct std::enable_if'中没有名为'type'的类型“。有人能指出我在这里做错了什么吗?

如果
有效,则启用_,因为替换从重载解析集中删除,编译器只考虑其他可行的重载。”

在您的示例中,实例化成员函数时不会发生替换,因为此时已知道模板参数
T
。实现尝试的最简单方法是创建默认为
T
的伪模板参数,并使用该参数执行SFINAE

template<typename T>
struct Point
{
  template<typename U = T>
  typename std::enable_if<std::is_same<U, int>::value>::type
    MyFunction()
  {
    std::cout << "T is int." << std::endl;
  }

  template<typename U = T>
  typename std::enable_if<std::is_same<U, float>::value>::type
    MyFunction()
  {
    std::cout << "T is not int." << std::endl;
  }
};
模板
结构点
{
模板
typename std::enable_if::type
MyFunction()
{

std::cout
enable\u如果
仅适用于推导的函数模板参数或专用类模板参数。您所做的不起作用,因为显然对于固定的
t=int
,第二个声明是错误的

这是如何做到的:

template <typename T>
void MyFreeFunction(Point<T> const & p,
                    typename std::enable_if<std::is_same<T, int>::value>::type * = nullptr)
{
    std::cout << "T is int" << std::endl;
}

// etc.

int main()
{
    Point<int> ip;
    MyFreeFunction(ip);
}
模板
void MyFreeFunction(点常量和点,
typename std::enable_if::type*=nullptr)
{

std::cout一个简单的解决方案是使用对工作者私有函数的委托:

template<typename T>
struct Point
{

  void MyFunction()
  {
     worker(static_cast<T*>(nullptr)); //pass null argument of type T*
  }

private:

  void worker(int*)
  {
    std::cout << "T is int." << std::endl;
  }

  template<typename U>
  void worker(U*)
  {
    std::cout << "T is not int." << std::endl;
  }
};
模板
结构点
{
void MyFunction()
{
worker(static_cast(nullptr));//传递类型为T的null参数*
}
私人:
无效工作程序(int*)
{

std::cout根据Praetorian的建议(但不改变函数的返回类型),这似乎有效:

#include <iostream>
#include <type_traits>

template<typename T>
struct Point
{
  template<typename U = T>
  void MyFunction(typename std::enable_if<std::is_same<U, int>::value, U >::type* = 0)
  {
    std::cout << "T is int." << std::endl;
  }

  template<typename U = T>
  void MyFunction(typename std::enable_if<!std::is_same<U, int>::value, float >::type* = 0)
  {
    std::cout << "T is not int." << std::endl;
  }
};

int main()
{
  Point<int> intPoint;
  intPoint.MyFunction();

  Point<float> floatPoint;
  floatPoint.MyFunction();
}
#包括
#包括
模板
结构点
{
模板
void MyFunction(typename std::enable_if::type*=0)
{
std::cout intPoint;
intPoint.MyFunction();
点浮点数;
floatPoint.MyFunction();
}

下面的点模板只能用int或float作为模板参数T进行实例化

回答这个问题:这里worker()的调用完全取决于method()调用的模板参数,但仍然由您控制类型

    template<typename T>
    struct Point
    {
        static_assert (
              std::is_same<T, int>()  ||
              std::is_same<T, float>()
            );

        template<typename U>
        void method(U x_, U y_)
        {
            if constexpr (std::is_same<T, U>()) {
                worker(x_, y_);
                return;
            }
            // else 
            worker(
                static_cast<T>(x_),
                static_cast<T>(y_)
            );
            return ;
        }


    private:

        mutable T x{}, y{};

        void worker(T x_, T y_)
        {
            // nothing but T x, T y
        }

    };
模板
结构点
{
静态断言(
std::是否相同()||
std::是否相同()
);
模板
无效方法(ux_uu,uy_uu)
{
如果constexpr(std::is_same()){
工人(x,y);
返回;
}
//否则
工人(
静态铸件(x),
静态演员阵容(y)
);
返回;
}
私人:
可变的tx{},y{};
无效工作者(T x_uu,T y_uu)
{
//除了T x,T y什么都没有
}
};

上述worker()当然可以工作,即使它被声明为静态的。出于一些合理的原因。上面的其他扩展是可能的(而且很简单),但让我们坚持回答。

我认为这遵循@Praetorian的解决方案,但我发现它更容易:

template<typename T>
struct Point
{
    template<typename U = T>
    std::enable_if_t<std::is_same<U, T>::value && std::is_same<T, int>::value>
    MyFunction()
    {
        std::cout << "T is int." << std::endl;
    }

    template<typename U = T>
    std::enable_if_t<std::is_same<U, T>::value && std::is_same<T, float>::value>
    MyFunction()
    {
        std::cout << "T is not int." << std::endl;
    }
};
模板
结构点
{
模板
std::如果启用,则启用
MyFunction()
{

std::cout相关问答:更新:C++20将允许
模板结构点{void MyFunction()需要(std::is_same_v);void MyFunction()需要(!std::is_same_v);}
。在这里,约束表达式是非依赖的和错误的是可以的——这只会使整个函数在重载解析过程中不那么受欢迎。在C++11中,SFINAE规则被修改了一点,因此SFINAE不会在返回类型时触发。简言之,这个答案是错误的。@Nawaz在gcc4.7.2上工作得很好,无法发布LWS关闭后的一个演示链接。一个ideone演示。@Nawaz:C++11标准到底在哪里说你不能再这样做了?这将是一个非常大胆的突破性改变,我不明白他们为什么要这样做。而且,如果是真的,(现在)惯用的
模板自动f(t&v)->decltype(v.foo())
SFINAE构造,用于检查成员,将不起作用。@Nawaz:这并不意味着返回类型中的替换不再是软错误。另一个线程中的问题是,在
meta
内部,您会得到错误,如果
enable\u
@Praetorian,您可以添加
static_assert(std::is_same::value,“不要指定模板参数!”);
来中断编译。变量参数只是提供更多信息的错误消息(其中的正确类型)。我见过这个解决方案,但它似乎真的破坏了代码的可读性。@DavidDoria:原始代码太过做作,无法提出更适合的建议。@DavidDoria如果您的情况是仅使用SFINAE检查某些类型是否相同(如果不匹配,则使用默认值)然后,为这些固定类型专门化
Point
的模板正是您想要的。您可以使用相同的实例化和更可读的定义。我真的很喜欢这样。我不认为我会使用它,但OP的示例是如此精心设计,这确实是一个很好的解决方案。static_cast(nullptr)从技术上讲,裁判官的建议并没有改变返回类型,而是改变了参数类型(即通过删除默认参数)。如果constexpr
仅从C++17开始可用,则问题被特别标记为C++11。
。此外,
mutable
是不需要的,可能是一个坏主意,因为
mutable
通常是这样。
template<typename T>
struct Point
{
    template<typename U = T>
    std::enable_if_t<std::is_same<U, T>::value && std::is_same<T, int>::value>
    MyFunction()
    {
        std::cout << "T is int." << std::endl;
    }

    template<typename U = T>
    std::enable_if_t<std::is_same<U, T>::value && std::is_same<T, float>::value>
    MyFunction()
    {
        std::cout << "T is not int." << std::endl;
    }
};