【问题标题】:Class vs. function template specialization [duplicate]类与函数模板专业化[重复]
【发布时间】:2020-07-25 07:21:01
【问题描述】:

我最近才从here 了解到 C++ 中的部分模板特化,它完美地解决了我需要一个模板类来对指针和非指针表现不同的问题。一个简化的例子是:

// main.cpp

template <typename T>
class C
{
public:
  C( const T& t ) : t_( t ) {}
private:
  T t_;
};

template <typename T>
class C<T*>
{
public:
  C( const T& t ) : t_( new T(t) ) {}
  ~C() { delete t_; }
private:
  T* t_;
};

int main( int argc, char* argv[] )
{
  C<int>  c1(4);
  C<int*> c2(2);

  return 0;
}

我想尝试将这个想法扩展到函数,但遇到了我不理解的编译器错误:

// main.cpp
#include <set>

template <typename T>
std::set<T> makeSet( size_t off )
{
  std::set<T> s;
  s.insert( T() + T(off) );
  return s;
}

template <typename T>
std::set<T*> makeSet<T*>( size_t off )
{
  std::set<T*> s;
  T* t = new T( T() + T(off) );
  s.insert( t );
  return s;
}

int main( int argc, char* argv[] )
{
  std::set<int>  s1 = makeSet<int>(4);
  std::set<int*> s2 = makeSet<int*>(2);

  delete *(s2.begin());

  return 0;
}

.

$ g++ --version && g++ -g ./main.cpp
g++ (GCC) 9.2.1 20190827 (Red Hat 9.2.1-1)
Copyright (C) 2019 Free Software Foundation, Inc.
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.

./main.cpp:13:38: error: non-class, non-variable partial specialization ‘makeSet<T*>’ is not allowed
   13 | std::set<T*> makeSet<T*>( size_t off )
      |                                      ^
./main.cpp: In function ‘int main(int, char**)’:
./main.cpp:23:37: error: call of overloaded ‘makeSet<int>(int)’ is ambiguous
   23 |   std::set<int>  s1 = makeSet<int>(4);
      |                                     ^
./main.cpp:5:13: note: candidate: ‘std::set<T> makeSet(size_t) [with T = int; size_t = long unsigned int]’
    5 | std::set<T> makeSet( size_t off )
      |             ^~~~~~~
./main.cpp:13:14: note: candidate: ‘std::set<T*> makeSet(size_t) [with T = int; size_t = long unsigned int]’
   13 | std::set<T*> makeSet<T*>( size_t off )
      |              ^~~~~~~~~~~
./main.cpp:24:38: error: call of overloaded ‘makeSet<int*>(int)’ is ambiguous
   24 |   std::set<int*> s2 = makeSet<int*>(2);
      |                                      ^
./main.cpp:5:13: note: candidate: ‘std::set<T> makeSet(size_t) [with T = int*; size_t = long unsigned int]’
    5 | std::set<T> makeSet( size_t off )
      |             ^~~~~~~
./main.cpp:13:14: note: candidate: ‘std::set<T*> makeSet(size_t) [with T = int*; size_t = long unsigned int]’
   13 | std::set<T*> makeSet<T*>( size_t off )
      |              ^~~~~~~~~~~

我对此有点怀疑,因为它看起来像是试图重载具有不同返回类型但具有相同参数的函数 - 我知道这在其他方面是非法的,但我认为因为这些是模板函数,指定调用函数时的模板类型(如上面的main())将允许消除歧义。

但我不确定编译器在第 13 行抱怨的是什么:non-class, non-variable partial specialization ‘makeSet&lt;T*&gt;’ is not allowed 错误是什么意思?

我在 C++ 中尝试做的事情是否可行? IE。是否可以制作一个模板函数,使其对指针和非指针模板类型的行为有所不同,并返回指定类型的 STL 容器?(C++ 98、03、11 和 14 之间的答案会有所不同吗? )

【问题讨论】:

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


    【解决方案1】:

    你可以试试这样的(C++17):

    template <typename T>
    std::set<T> makeSet( size_t off )
    {
      std::set<T> s;
      if constexpr(std::is_pointer_v<T>)
      {
        using U = std::remove_reference_t<decltype(*std::declval<T>())>;
        s.insert(new U( U() + U(off) ));
      }
      else
      {
        s.insert( T() + T(off) );
      }
      return s;
    }
    

    【讨论】:

      【解决方案2】:

      non-class, non-variable partial specialization ‘makeSet&lt;T*&gt;’ is not allowed 错误是什么意思?

      让我们看一些关于部分模板专业化的文档from cppreference.com

      允许为给定的模板参数类别定制类 [和变量 (C++14 起)] 模板。

      类和变量模板允许部分特化。编译器告诉您,您的模板既不是用于变量的类。因此,不允许部分特化。

      编译器消息的一个不太令人困惑的措辞是:不允许对函数模板进行部分特化。


      至于能做什么,可以用合适的operator()声明一个类模板。在某些情况下,这与使用函数模板一样好。

      【讨论】:

      • 不错的建议 RE:operator() - 谢谢!
      猜你喜欢
      • 1970-01-01
      • 2013-12-27
      • 2021-12-11
      • 2017-12-10
      • 1970-01-01
      • 1970-01-01
      • 2011-10-29
      • 2016-09-12
      相关资源
      最近更新 更多