[英]Why does this template argument deduction fail when a default value is given?
以下代碼有效:
template <typename T>
struct Foo
{
template <typename OStream>
static void default_print_function(OStream &, const T &);
template <typename OStream, typename PrintFunction>
void print(
OStream &,
const PrintFunction & = &Foo<T>::default_print_function<OStream>) const;
template <typename OStream>
void print(OStream &) const;
};
template <typename T>
template <typename OStream>
void Foo<T>::default_print_function(OStream & o, const T & value)
{
o << value;
}
template <typename T>
template <typename OStream, typename PrintFunction>
void Foo<T>::print(OStream & o, const PrintFunction & f)
const
{
T test_value = 123;
o << "TEST: ";
f(o, test_value);
}
template <typename T>
template <typename OStream>
void Foo<T>::print(OStream & o)
const
{
print(o, &default_print_function <OStream>);
}
#include <iostream>
int main()
{
Foo <int> foo;
foo.print(std::cerr, &Foo<int>::default_print_function<std::ostream>);
std::cerr << std::endl;
foo.print(std::cerr);
std::cerr << std::endl;
}
但是,如果我注釋掉void print (OStream &) const
重載:
template <typename T>
struct Foo
{
template <typename OStream>
static void default_print_function(OStream &, const T &);
template <typename OStream, typename PrintFunction>
void print(
OStream &,
const PrintFunction & = &Foo<T>::default_print_function<OStream>) const;
template <typename OStream>
void print(OStream &) const;
};
template <typename T>
template <typename OStream>
void Foo<T>::default_print_function(OStream & o, const T & value)
{
o << value;
}
template <typename T>
template <typename OStream, typename PrintFunction>
void Foo<T>::print(OStream & o, const PrintFunction & f)
const
{
T test_value = 123;
o << "TEST: ";
f(o, test_value);
}
/*template <typename T>
template <typename OStream>
void Foo<T>::print(OStream & o)
const
{
print(o, &default_print_function <OStream>);
}*/
#include <iostream>
int main()
{
Foo <int> foo;
foo.print(std::cerr, &Foo<int>::default_print_function<std::ostream>);
std::cerr << std::endl;
foo.print(std::cerr);
std::cerr << std::endl;
}
然后它將無法編譯:
test.cpp: In function ‘int main()’:
test.cpp:54:25: error: no matching function for call to ‘Foo<int>::print(std::ostream&)’
foo .print (std :: cerr);
^
test.cpp:8:7: note: candidate: template<class OStream, class PrintFunction> void Foo<T>::print(OStream&, const PrintFunction&) const [with OStream = OStream; PrintFunction = PrintFunction; T = int]
void print (
^~~~~
test.cpp:8:7: note: template argument deduction/substitution failed:
test.cpp:54:25: note: couldn't deduce template parameter ‘PrintFunction’
foo .print (std :: cerr);
print
的第二個參數的默認值拼寫方式在我看來完全等同於在main
函數中第一次調用時拼寫的方式。
foo .print (std :: cerr, & Foo <int> :: default_print_function <std :: ostream>);
那么為什么可以在此調用中推導出模板參數,而不是在默認參數中推導出
const PrintFunction & = & Foo <T> :: default_print_function <OStream>
?
這是一個非推斷的上下文:
未推斷的上下文:
...
4)在函數參數的參數類型中使用的模板參數,該參數具有在正在進行參數推斷的調用中使用的默認參數
編輯 (為什么它是一個非推斷的上下文)
因為非推斷的上下文有一個好處:它允許使用類型,如果它可以從其他地方獲得。
考慮這個例子:
template<class T>
void foo(T, T = 1.0) {};
int main() {
foo(2);
}
這是有效的代碼。 但如果它不是一個非推斷的背景,那么推論就會發生沖突。 假設程序員想要轉換而不是失敗,這有點合理。
另一方面,類型基本上在別處給出(默認參數在聲明中給出)。 例如,如果你將decltype
轉換為模板參數,你的代碼就可以了:
template <typename OStream, typename PrintFunction = decltype(&Foo<T>::default_print_function<OStream>)>
總而言之,我們失去了任何東西,使其成為一個非演繹的背景。 此外,當在其他地方提供類型時,我們可以轉換默認參數類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.