2013-03-09 91 views
4

我想指定一个类的模板转换运算符的模板参数,但我似乎无法得到正确的语法。在http://liveworkspace.org/code/35sqXe$4C++如何指定一个类的模板转换运算符的参数

#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; 
}  

相同的代码当与克++ 4.7.2

$ 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)

$ 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; 
          ^

当与编译铛++编译编译3.2

$ 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

$ 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; } 
       ^

其他编译则警告,国际商会似乎很好地工作。

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

编辑

由于Yakk问我原来的/实际的问题是什么:
我有一个类PTR(模板上它指的类型),我想有一个转换的PTR为constŤ (虽然我知道在这种情况下并不重要),如果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的有效使用,并且可以工作如预期。

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函数,执行此操作的语法是显而易见的并且有效(请参阅上面的operator())。对于这个例子:

Ptr<const int> ci; 
ci.operator Ptr<const int><const int, void>(); // assuming this syntax is valid 

空隙(或任何其他类型的有)将指定的转换运算符的第二个模板参数,并将含有enable_if默认将不被考虑。当我试图使它不存在时,这将使这种方法存在。

但是gcc,clang和msvc似乎对这个语法有问题。我假设由于转换运算符拼写为operator typename,因此模板参数会让编译器认为它们是针对typename而不是操作符。

确实有一些解决方法(只包括转换运算符,当T已经是const时不会转换为const T),但这是针对此特定问题的。也许不可能为转换运算符指定模板参数,因此,将这些类型推断/默认是没问题的。或者也许有一个语法(icc似乎把它...),所以我打开自己,以指定模板参数和实例化方法,我不希望他们的用户。我已经为我的具体问题找到了解决方案(在类型确实重要的时候,在转换运算符的类型检查中使用static_assert),但这个问题是关于C++语言及其语法的。顶部的类C只是我想要搜索该语法的最简单方法。

+2

你可以用”不要这样做。如果您有转换运算符模板,则其返回类型必须使用该模板中的参数。没有办法指定参数。 – Xeo 2013-03-09 01:04:16

+0

我实际上并不想改变返回类型。这是为了根据类的模板类型“enable_if”转换运算符的动机。由于我无法将enable_if作为返回类型或参数的一部分(没有任何参数),因此我将其作为模板类型。然后我想知道该模板类型是否在成员的实例中明确指定,如果转换操作符不应该出现在类中,那么是否可以使转换操作符出现在类中。但我无法弄清楚如何指定模板参数。这是我可以想到的搜索该语法的最简单的方法。 – 2013-03-09 04:21:33

+0

因为我正在寻找更多的语言,而不是真正解决特定的问题,所以如果不支持这种语法,我将不胜感激指向C++标准的指针(最好是C++ 11)。 – 2013-03-09 04:34:39

回答

0

这里有一个问题的答案,你也没问,该怎么办SFINAE enable_if操作上的隐式转换运营商,启用或取决于模板参数类本身禁用它们:

#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意味着我们生成了大量的隐式类型转换,但它相对接近。

这里是如何模板参数传递给铸造运营商,或者至少一种方式接近它:

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参数。这个int参数完全没有用,除了允许显式地将模板参数传递给operator int_wrapper<n>。虽然返回int_wrapper<...>不是int的完美替代品,但它非常接近。

+0

整洁,但我正在寻找更多的语法,然后为这个特定的人为的例子工作。 – 2013-03-09 04:31:15

+0

您的编辑实际上涉及激励问题(请参阅我的问题的编辑)。问题是,如果指定转换运算符的模板参数的语法存在,我可以说'struct Mytype {}; Foo <2> two; Mytype mt = two.operator Mytype ();'。我的问题是:这个语法是否存在,它是什么,或者这个语法不存在,我不必担心这个问题吗? – 2013-03-11 14:59:40

+0

创建'T get_as ()'方法。然后'template ()),T> :: value> :: type> operator T(){return get_as (); }'为了将'运算符T'转发给'get_as'。然后,当你需要语法来明确地操作模板参数时,你可以调用'get_as',并且当它被隐式调用时,'operator T'只需调用'get_as'。 – Yakk 2013-03-11 17:41:51

1

你试图达到的目标有点不清楚......真的没有什么理由让所有这些成员函数成为一般的模板,你可以使它们以adder为参数的常规函数​​。

get功能,很好,并没有真正得到,而是增加,所以你可以把它叫做add。函数调用运算符operator()()很可能以int为参数。转换运算符为int从字面上看没有意义作为模板,并且不能像定义的那样调用。如果你坚持具有getoperator()为模板,你可以打电话给他们:

C c(0); 
c.get<5>(); // 5 
c<5>();  // 5 

但我建议你重新设计,决定你真正需要和模板是否要走的路... (请注意,即使是在非模板的版本,它并没有真正意义的有转化为int,需要一个,你是不是转换,但创建一个不同的int!)

+0

我的问题更多的是关于语法的搜索,而不是关于特定类的创作。我注意到,在许多模板化的“operator xxx”成员中,如果您愿意使用class_instance.operator xxx (member_argument)表单,但指定模板参数没有问题,但我无法弄清楚转换运营商。 – 2013-03-09 04:28:40

+0

另外,我无法获得语法c <5>();上班。 – 2013-03-09 04:51:57

+0

这可能是不可能的......我虽然会诚实但我没有尝试。这是我不经常使用的一个特性(我试图弄清楚他们在做什么,并且在我的代码库中转换和函数调用操作符不常见,为此优先选择命名函数) – 2013-03-11 13:07:13

相关问题