【问题标题】:partial specialization of function templates函数模板的部分特化
【发布时间】:2011-06-27 12:29:09
【问题描述】:

在下面的代码sn-p中,

template<typename T1>
void func(T1& t)
{
    cout << "all" << endl;
}

template<typename T2>
void func(T2 &t)
{
    cout << "float" << endl;
}

// I do not want this
// template<> void func(float &t)

int main()
{
    int i; float f;
    func(i); // should print "all"
    func(f); // should print "float" 
    return 0;
}

我想修改模板,通过传递除浮点数以外的任何类型将打印“全部”,传递浮点数将打印“浮点数”。我不想要模板专业化,而是有部分专业化,它将根据输入类型相应地采取行动。我该怎么做。提前致谢。

好吧,我目前面临的情况是, 我需要定义以下内容,

template<typename T1>
void func(T1 &t)
{
    cout << "t1" << endl;
}

template<typename T2>
void func(T2 &t)
{
    cout << "t2" << endl;
}

以下调用应打印“t2”

func(int) // print "t2"
func(float) // print "t2"
func(string) // print "t2"

以下调用应打印“t1”

func(char) // print "t1"
func(xyz) // print "t1"
...
func(abc) // print "t1"

类似于上面的某种分组,其中很少有人应该调用部分专业化实现,而其他人应该调用默认实现。

【问题讨论】:

  • 为什么不使用模板专业化?这就是它的用途。
  • 虽然您不能部分特化模板函数,但函数特化通常是个坏主意,请参阅:gotw.ca/publications/mill17.htm
  • 我不打算回答,因为:你还没有解释“int X”有什么用处。

标签: c++ templates template-specialization function-templates


【解决方案1】:

您不能在 C++ 中部分特化函数。

也许这不是你的意思。您可以使用 boost::is_same&lt;T1, T2&gt; 之类的模板根据给定的模板参数执行条件逻辑。你也可以在任何你想使用任何其他类型的地方使用T,例如typeid(T).name()

template <typename T>
void foo(T&) {
   if (boost::is_same<T, int>::value)
      std::cout << "int lol";
   else
      std::cout << typeid(T).name();
}

(虽然我不建议使用 typeid().name(),因为它的值不是由标准指定的,并且可以从代码中编写的类型到损坏的符号或 的歌词扑克脸。)

附录 像其他回答者一样,我个人会选择模板专业化本身或只是简单的 ol' 函数重载。我不知道你为什么讨厌他们,但这就是他们的目的。

【讨论】:

    【解决方案2】:

    您可以将函数重载与模板结合使用。所以:

    #include <iostream>
    
    template<typename T>
    void func(T& t)
    {
        std::cout << "all" << std::endl;
    }
    
    void func(float& f)
    {
        std::cout << "float" << std::endl;
    }
    
    int main()
    {
        int i; float f;
        func(i); // prints "all"
        func(f); // prints "float" 
        return 0;
    }
    

    【讨论】:

      【解决方案3】:

      正如 Tomalak 在他的回答中已经说过的,您不能部分专门化模板函数,但如果您将函数更改为模板类中的静态成员函数,则可以这样做。

      但是,更好的方法是函数重载。

      【讨论】:

        【解决方案4】:

        为您的条件编写一个类型特征类:

        template<class T>
        struct IsIntFloatOrString {
          enum { value = boost::is_same<T, int>::value
                      or boost::is_same<T, float>::value
                      or boost::is_same<T, string>::value };
        };
        

        使用boost::enable_if 和 disable_if:

        template<typename T1>
        typename boost::enable_if<IsIntFloatOrString<T1> >::type
        func(T1 &t) {
          cout << "t1" << endl;
        }
        
        template<typename T2>
        typename boost::disable_if<IsIntFloatOrString<T2> >::type
        func(T2 &t) {
          cout << "t2" << endl;
        }
        

        【讨论】:

        • 如果我想要像“t3”这样的其他类型特征专业化怎么办?
        • @PrabhuJayaraman:没关系,你只需要布尔条件来启用_/禁用_if;例如另一个特征类并使用 (!a and b) 和 (a and !b) 作为条件。
        【解决方案5】:

        在任意数量的条件下,这是如何使它在没有丑陋的语法 a and !b and !c 的情况下为 enable_if 工作。

        如果我们知道偏特化对工作函数不起作用,而是对类起作用,那么让我们使用类吧!我们应该对人们隐藏它,但我们可以使用它们!

        好的,代码:

        #include <type_traits>
        #include <iostream>
        
        
        template <typename T>
        class is_int_or_float : public std::integral_constant<bool, std::is_same<T, int>::value || std::is_same<T, float>::value> {
        };
        
        
        template<typename T, typename Enable = void> //(2)
        struct Helper {
            static void go(const T&) {
                        std::cout << "all"<< std::endl;
                }
        };
        
        template<typename T>
        struct Helper<T, typename std::enable_if<is_int_or_float<T>::value>::type> { // (3)
                static void go(const T&) {
                        std::cout << "int or float" << std::endl;
                }
        };
        
        template<typename T>
        struct Helper<T, typename std::enable_if<std::is_pointer<T>::value>::type> { // (3)
                static void go(const T&) {
                        std::cout << "pointer" << std::endl;
                }
        };
        
        template<typename T>
        void func(const T& arg) {
                Helper<T>::go(arg); // (1)
        }
        int main() {
                char c;
                int i;
                float f; 
                int* p;
                func(c);
                func(i);
                func(f);
                func(p);
        }
        

        (1) 首先只针对每个类型调用助手。没有专门的功能。
        (2) 这里我们添加一个虚拟参数。我们不必在调用时指定它,因为它默认为void (3) 在 3 中,我们只给出 void,当我们允许 T 和其他任何东西时(或者在我们的例子中是 SFINAE)。一件重要的事情是我们不应该允许一些T 两次或更多。

        注意事项:

        1. 我们还可以将默认类型更改为std::true_type,之后我们将能够摆脱std::enable_ifstd::enable_if&lt;some_trait&lt;T&gt;::value&gt; 将更改为仅some_trait&lt;T&gt;::type)。我不确定是哪个

        2. 此代码使用 C++11 中的类型特征。如果您没有 c++11 支持,您可以编写自己的特征或使用来自boost的类型特征@

        Live example

        【讨论】:

          猜你喜欢
          • 2011-12-25
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-08-24
          • 2012-12-15
          • 1970-01-01
          相关资源
          最近更新 更多