SFINAE如何正常工作?

时间:2018-02-07 22:21:49

标签: c++ sfinae enable-if

我有SFINAE的问题。我错过了一些重要的事情并且阅读其他问题没有帮助:(

以下是代码:

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

// version with template class

template<typename T, typename = std::enable_if_t<
                std::is_integral<std::remove_reference_t<T>>::value
             || std::is_floating_point<std::remove_reference_t<T>>::value
             >
         >
struct to_my_string
{
    std::string operator()(T numerical)
    {
        return std::to_string(numerical);
    }
};

template<typename T, typename = std::enable_if_t< std::is_same<T, std::string>::value > >
struct to_my_string
{
    std::string operator()(T str)
    {
        return "'" + str + "'";
    }
};


// version with template method

template<typename T, typename = std::enable_if_t<
                std::is_integral<std::remove_reference_t<T>>::value
             || std::is_floating_point<std::remove_reference_t<T>>::value
             >
         >
std::string to_string_method(T numerical)
{
    return std::to_string(numerical);
}

template<typename T, typename = std::enable_if_t< std::is_same<T, std::string>::value > >
std::string to_string_method(T str)
{
    return "'" + str + "'";
}

int main()
{
    std::cout << "start" << std::endl;
    return 0;
}

我已经粘贴了两种方法 - 一种类和一种方法。两者产生类似的错误: 以下是g ++的错误(clang给出了类似的错误):

g++ --std=c++14 sfinae_failure.cpp

sfinae_failure.cpp:21:12: error: redefinition of default argument for ‘class<template-parameter-1-2>’
 struct to_my_string
        ^
sfinae_failure.cpp:7:26: note: original definition appeared here
 template<typename T, typename = std::enable_if_t<
                      ^
sfinae_failure.cpp:43:17: error: redefinition of ‘template<class T, class> std::__cxx11::string to_string_method(T)’
 std::string to_string_method(T str)
             ^
sfinae_failure.cpp:37:17: note: ‘template<class T, class> std::__cxx11::string to_string_method(T)’ previously declared here
 std::string to_string_method(T numerical)
             ^

我的主要问题是为什么它不起作用,即使我在enable_if_t中使用T类型。我错过了什么?

附加的问题是 - 我认为模板类/方法在使用时会被实例化。正如你在主方法中看到的那样 - 它们不是。

即使这个话题被多次触及,我也非常感谢你的帮助......

2 个答案:

答案 0 :(得分:2)

您的课程模板的错误是因为您无法重新定义课程模板,它与SFINAE无关。

template<class A = int> struct foo {};
template<class A = double> struct foo {};

即使没有实例化,这段代码也无法编译。

您的函数的错误是因为默认模板参数是函数模板参数签名的一部分。

template<class A, class B = int> void bar() {}
template<class A, class B = double> void bar() {}

即使没有实例化,这段代码也无法编译,因为它们的模板参数签名是相同的:

template<class A, class B> void bar() {}

因此重新定义。

答案 1 :(得分:1)

修正版本:

template<typename T, typename Enabler = void> struct to_my_string;

template <typename T>
struct to_my_string<T, std::enable_if_t<
                std::is_integral<std::remove_reference_t<T>>::value
             || std::is_floating_point<std::remove_reference_t<T>>::value
             >>
{
    std::string operator()(T numerical) const
    {
        return std::to_string(numerical);
    }
};

template<typename T>
struct to_my_string<T, std::enable_if_t<std::is_same<T, std::string>::value>>
{
    std::string operator()(const T& str) const
    {
        return "'" + str + "'";
    }
};


// version with template method
template<typename T, std::enable_if_t<
                std::is_integral<std::remove_reference_t<T>>::value
             || std::is_floating_point<std::remove_reference_t<T>>::value
             , void*> = nullptr
         >
std::string to_string_method(T numerical)
{
    return std::to_string(numerical);
}

template<typename T, std::enable_if_t< std::is_same<T, std::string>::value, void*> = nullptr>
std::string to_string_method(T str)
{
    return "'" + str + "'";
}