首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c++如何为类的模板化转换运算符指定参数

c++如何为类的模板化转换运算符指定参数
EN

Stack Overflow用户
提问于 2013-03-09 08:57:00
回答 2查看 1.7K关注 0票数 4

我试图为类的模板化转换操作符指定模板参数,但我似乎无法获得正确的语法。

代码语言:javascript
复制
#include <iostream>
using namespace std;

class C
{
   int i_;
public:
   C(int i) : i_(i) {}
   template<int adder> int get() { return i_ + adder; }
   template<int adder> int operator()() { return i_ + adder; }
   template<int adder> operator int() { return i_ + adder; } 
   // If I add a default argument to operator int()'s adder template parameter this compiles fine 
   // (of course, I still can't figure out how to specify it...)
};

int main(int, char*[])
{
   C c(10);
   cout << c.get<2>() << endl;            // I can specify template argument here the regular way.
//   cout << c() << endl;                 // No template argument specified, so I wouldn't have expected this to work.
   cout << c.operator()<3>() << endl;     // We have to call it this way.
//    cout << (int)c << endl;             // In the same vein I wouldn't expect this to work either.
   cout << c.operator int<4>() << endl;   // But how do I specify template argument here? This seems to be an error for some compilers.
   return 0;
}    

http://liveworkspace.org/code/35sqXe$4上的相同代码

使用g++ 4.7.2编译时

代码语言:javascript
复制
$ g++ -std=c++11 -Wall -W -pedantic "template conversion operator.cpp"

Compilation finished with errors:
source.cpp: In function 'int main(int, char**)':
source.cpp:23:23: error: 'int' is not a template
source.cpp:23:30: error: no matching function for call to 'C::operator int()'
source.cpp:23:30: note: candidate is:
source.cpp:11:24: note: template<int adder> C::operator int()
source.cpp:11:24: note: template argument deduction/substitution failed:
source.cpp:23:30: note: couldn't deduce template parameter 'adder'

使用g++ 4.8.0 (20130224)编译时

代码语言:javascript
复制
$ g++ -std=c++11 -Wall -W -pedantic "template conversion operator.cpp"

Compilation finished with errors:
source.cpp: In function 'int main(int, char**)':
source.cpp:23:23: error: 'int' is not a template
    cout << c.operator int<4>() << endl; 
                       ^
source.cpp:23:30: error: no matching function for call to 'C::operator int()'
    cout << c.operator int<4>() << endl;
                              ^
source.cpp:23:30: note: candidate is:
source.cpp:11:24: note: template<int adder> C::operator int()
    template<int adder> operator int() { return i_ + adder; }
                        ^
source.cpp:11:24: note: template argument deduction/substitution failed:
source.cpp:23:30: note: couldn't deduce template parameter 'adder'
    cout << c.operator int<4>() << endl;
                              ^

使用clang++ 3.2编译时

代码语言:javascript
复制
$ clang++ -std=c++11 -Wall -W -pedantic "template conversion operator.cpp"

Compilation finished with errors:
source.cpp:23:12: error: reference to non-static member function must be called
   cout << c.operator int<4>() << endl;
           ^~~~~~~~~~~~~~
source.cpp:23:30: error: expected expression
   cout << c.operator int<4>() << endl;
                             ^
2 errors generated.

使用icc 13.0.1编译时

代码语言:javascript
复制
$ icc -std=c++11 -Wall -W -pedantic "template conversion operator.cpp"

Compilation finished with warnings:
source.cpp(11): warning #488: constant "adder" is not used in declaring the parameter types of function template "C::operator int"
     template<int adder> operator int() { return i_ + adder; }
                  ^

除了警告之外,icc似乎工作得很好。

这些是编译器错误吗?或者是我的语法出了问题?

编辑

因为Yakk问我的原始/实际问题是什么:

我有一个类Ptr (在它所指向的类型上模板化),我想要有一个到Ptr到const T的转换(尽管我知道在这种情况下这并不重要),如果T已经是const类型,我希望转换运算符不在那里。由于您没有为转换操作符指定返回类型或方法参数,因此我将enable_if作为方法的模板参数的一部分。

正如Yakk (和其他问题中的其他人)所发布的那样,简单的template <typename = typename std::enable_if<!std::is_const<T>::value>::type>不起作用,因为当Ptr被实例化时,T在编译器到达这个声明时是已知的。因为没有推导出T,所以没有SFINAE。因为我们知道!is_const<T>::value是假的,所以没有“类型”成员,声明是无效的。使模板依赖于新类型(U),推导出U,然后检查U与T是否相同,T是否为常量,然后使用无效声明是SFINAE的有效使用,并按预期工作。

代码语言:javascript
复制
template <typename T>
class Ptr
{
   template <typename U,
             typename = typename std::enable_if<std::is_same<T, U>::value &&
                                                !std::is_const<U>::value>::type>
   operator Ptr<const U>() const { return active; }
};

但后来我对自己说,这是一个模板化的成员函数。这些模板参数不必保留为默认值,它们可以由实例化该函数的任何人指定。对于任何其他操作符xxx函数,执行此操作的语法是显而易见的并且有效(参见上面的操作符())。在此示例中:

代码语言:javascript
复制
Ptr<const int> ci;
ci.operator Ptr<const int><const int, void>(); // assuming this syntax is valid

空(或其中的任何其他类型)将指定转换操作符的第二个模板参数,并且不考虑包含enable_if的默认值。这将使此方法在我试图使其不存在时仍然存在。

但gcc、clang和msvc似乎在这种语法上存在问题。我假设因为转换操作符是拼写类型名,所以拥有模板参数会使编译器认为它们是针对operator typename而不是操作符的。

确实有一些变通方法(只需要包括转换操作符,当T已经是const时转换成const T不会有任何影响),但这是针对这个特定问题的。也许不可能为转换运算符指定模板参数,因此,让这些类型被推导/缺省是可以的。或者可能有它的语法(icc似乎接受它...),所以我向用户开放,指定模板参数并在我不需要的地方实例化方法。我已经有了针对我的特定问题的解决方案(在类型确实重要的时候,在转换操作符中对类型检查使用static_assert ),但是这个问题是关于C++语言及其语法的。顶部的类C是我所能想到的搜索该语法的最简单的方法。

EN

回答 2

Stack Overflow用户

发布于 2013-03-09 10:36:45

现在还不清楚你想要达到什么目的……没有什么好的理由让所有的成员函数都成为模板,你也可以让它们成为以adder为参数的常规函数。

get函数并不是真正的get,而是adds,所以您可以将其称为add。函数调用运算符operator()()可以很好地将int作为参数。从字面上看,int的转换运算符作为模板没有任何意义,并且不能按照定义调用它。如果您坚持使用getoperator()作为模板,您可以这样调用它们:

代码语言:javascript
复制
C c(0);
c.get<5>(); // 5
c<5>();     // 5

但我建议你重新考虑设计,决定你真正需要的是什么,模板是否是可行的……(请注意,即使在非模板化版本中,转换为接受某个值的int也没有实际意义,您不是在转换,而是创建一个不同的int!)

票数 1
EN

Stack Overflow用户

发布于 2013-03-09 09:40:27

这是你没有问到的问题的答案,如何在隐式类型转换操作符上执行SFINAE enable_if操作,根据类本身的模板参数来启用或禁用它们:

代码语言:javascript
复制
#include <iostream>
#include <type_traits>

template<int n>
struct Foo {
   template<typename T,typename=typename std::enable_if<std::is_convertible<T,int>::value && (n!=0)>::type>
   operator T() const { return n; }
};

int main() {
   Foo<0> zero;
   Foo<1> one;
   int x = 0;
   x = one;
   int y = 0;
   // y = zero; -- does not compile, because Foo<0> cannot be converted to int
   std::cout << x << "," << y << "\n";
}

这并不完美,因为is_convertible意味着我们生成了一大堆隐式类型转换,但它是相对接近的。

下面是如何将模板参数传递给转换运算符,或者至少是近似它的一种方法:

代码语言:javascript
复制
template<int n>
struct int_wrapper {
  int i;
  operator int() const { return i; }
  int_wrapper( int i_ ):i(i_) {}
};
// in class C:
template<int adder> operator int_wrapper<adder>() { return i_ + adder; } 

在这里,我创建了一个玩具类型int_wrapper,它打包了int参数。除了允许显式地将模板参数传递给operator int_wrapper<n>之外,这个int参数完全没有使用。虽然返回int_wrapper<...>不是int的完美替代品,但它非常接近。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/15305891

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档