簡體   English   中英

模板 class 中構造函數的條件定義

[英]Conditional definition of constructor in template class

我想要編譯以下內容:

#include <type_traits>

template<typename T>
class C {
public:
    C() {}
    C( const C &that ) {}
};

void foo( const C<const char> &c );

int main() {
    C<const int> i;

    foo( C<char>{} );
}

當然,它沒有,因為foo期望C<const char> ,而我正在傳遞C<char> 所以我想添加一個從C<T>C<const T>的隱式轉換。 第一次嘗試,我們將以下構造函數添加到C

C( const C< std::remove_const_t<T> > &that ) {}

這不起作用,因為如果T本身不是 const,則此定義與復制構造函數相同,這意味着我們重新定義了相同的構造函數兩次:

so.cpp: In instantiation of ‘class C<char>’:
so.cpp:17:18:   required from here
so.cpp:9:5: error: ‘C<T>::C(const C<typename std::remove_const<_Tp>::type>&) [with T = char; typename std::remove_const<_Tp>::type = char]’ cannot be overloaded with ‘C<T>::C(const C<T>&) [with T = char]’
     C( const C< std::remove_const_t<T> > &that ) {}
     ^
so.cpp:7:5: note: previous declaration ‘C<T>::C(const C<T>&) [with T = char]’
     C( const C &that ) {}

第二次嘗試,嘗試使用enable_if

template< std::enable_if_t< std::is_const_v<T>, int > = 0 >
C( const C< std::remove_const_t<T> > &that ) {}

這是行不通的。 由於模板不依賴於構造函數的 arguments 中所做的任何推導,因此評估得太早:

so.cpp: In instantiation of ‘class C<char>’:
so.cpp:18:18:   required from here
so.cpp:10:5: error: no type named ‘type’ in ‘struct std::enable_if<false, int>’
     C( const C< std::remove_const_t<T> > &that ) {}
     ^

讓我們人為地讓它依賴於arguments,那么:

template<
        typename V,
        std::enable_if_t<
                std::is_const_v<T> && std::is_same_v<T, V>,
                int
        > = 0
>
C( const C< std::remove_const_t<V> > &that ) {}

我不確定為什么會失敗。 我收到以下錯誤:

so.cpp: In function ‘int main()’:
so.cpp:24:10: error: invalid initialization of reference of type ‘const C<const char>&’ from expression of type ‘C<char>’
     foo( C<char>{} );
          ^~~~~~~~~
so.cpp:19:6: note: in passing argument 1 of ‘void foo(const C<const char>&)’
 void foo( const C<const char> &c );
      ^~~

我懷疑推論發生得太深,編譯器無法理解它需要進行什么替換。

我該如何解決這個問題?

Ps 是的,我知道在這種情況下我可以使用隱式復制構造函數。

You can use SFINAE on function but function should be template, and condition should depend of that template, remember that T from class is fixed for the member function:

template<typename T>
class C {
public:
    C() {}
    C( const C &that ) {}

    template <typename U,
              std::enable_if_t<std::is_same_v<U, std::remove_const_t<T>>, int> = 0>
    C( const C<U> &that ) {}
};

演示

在 C++20 中會有很好的語法:

template<typename T>
class C {
public:
    C() {}
    C( const C &that ) {}
    C( const C< std::remove_const_t<T> > &that ) requires(std::is_const<T>::value) {}
};

對於您的代碼:

template< std::enable_if_t< std::is_const_v<T>, int > = 0 >
C( const C< std::remove_const_t<T> > &that ) {}

不是替換上下文,參數由 class 修復,您有硬錯誤而不是預期的 SFINAE。

為了

template<
        typename V,
        std::enable_if_t<
                std::is_const_v<T> && std::is_same_v<T, V>,
                int
        > = 0
>
C( const C< std::remove_const_t<V> > &that ) {}

您可能有 SFINAE,但V不可推導,因此您必須提供它,但不能在調用站點執行它,因為它是構造函數。

簡單的解決方法是提供默認值:

 template<
        typename V = T,
        std::enable_if_t<
                std::is_const_v<T> && std::is_same_v<T, V>,
                int
        > = 0
>
C( const C< std::remove_const_t<V> > &that ) {}

演示

(由於 V 是必需的 T,您可以刪除std::is_same_v<T, V>但將std::is_const_v<T>更改為std::is_const_v<V>以獲得 SFINAE)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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