簡體   English   中英

為什么在給出默認值時此模板參數推斷失敗?

[英]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>

這是一個非推斷的上下文:

cppreference

未推斷的上下文:

...

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM