2013-03-09 83 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

相關問題