如何创建一个使用现有类 A 作为参数 a 的模板,并保持类 A 的实例不可复制和不可分配?

问题描述 投票:0回答:1

如何创建一个使用现有类 A 作为参数 a 的模板,并保持类 A 的实例不可复制和不可分配?

我想创建该模板以防止人们意外复制类,例如

protected
可以防止人们意外访问,并且
const
可以防止人们意外修改。

这是我的目标的简化版本:

NonCopyable<std::vector<int>> vec1{1, 2, 3};
NonCopyable<std::vector<int>> vec2(vec1);    // should not compile
vec2 = vec1;                                 // should not compile

假设我只能按原样采用原始类并且不想从该类派生,那么实现此行为的合适模板是什么? 注意:这不是如何使用不带继承的模板使现有类不可复制和不可分配?的重复。问题的编辑被审稿人拒绝,因为与最初的意图有很大的偏差。因此,这个问题必须被视为一个新问题。

如何使用不继承的模板使现有类不可复制和不可分配?
c++ templates
1个回答
0
投票

首先:没有这样的模板可以防止人们在可能的情况下复制数据。 代码

这里是模板类的代码,作为包装器作为起点,以防止使用复制构造函数或复制运算符进行意外复制。

#include <vector> template< typename T > struct NonCopyable { private: T value; public: NonCopyable( const NonCopyable<T>& t ) noexcept = delete; NonCopyable( NonCopyable<T>& t ) noexcept = delete; NonCopyable( NonCopyable<T>&& t ) noexcept = delete; template< typename... Targs > NonCopyable( const Targs... args ) noexcept : value{ args... } { } operator T&() const = delete; NonCopyable& operator = ( const NonCopyable& ) = delete; NonCopyable& operator = ( NonCopyable& ) = delete; NonCopyable& operator = ( NonCopyable&& ) = delete; }; int main( [[maybe_unused]] int argc, [[maybe_unused]]char* argv[] ) { NonCopyable< std::vector<int> > vec1{ 1, 2, 3, 4 }; //NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error: /* src/test2_2.cpp:25:48: error: use of deleted function ‘NonCopyable<T>::NonCopyable(NonCopyable<T>&) [with T = std::vector<int>]’ 25 | NonCopyable< std::vector<int> > vec2( vec1 ); // should not compile | ^ */ //vec2 = vec1; // would lead to the following compiler error: /* src/test2_2.cpp:31:12: error: use of deleted function ‘NonCopyable<T>& NonCopyable<T>::operator=(NonCopyable<T>&) [with T = std::vector<int>]’ 31 | vec2 = vec1; | ^~~~ */ return 0; }

免责声明

因此,模板没有任何用处,但可以通过访问该值的接口来丰富。请参阅下面的示例。请同时考虑到公开的信息越多,就越容易推断出价值,从而可以创建副本。

访问值的示例

假设,它被认为足以防止意外使用复制并使用通用接口访问

value

。以下解决方案是处理

value

的示例。

#include    <vector>
#include    <functional>
#include    <iostream>

template< typename T >
struct NonCopyable
{
private:
    T   value;
public:
    NonCopyable( const NonCopyable<T>& t ) noexcept = delete;
    NonCopyable( NonCopyable<T>& t ) noexcept = delete;
    NonCopyable( NonCopyable<T>&& t ) noexcept = delete;
    template< typename... Targs >
    NonCopyable( const Targs... args ) noexcept : value{ args... } {
    }
    operator T&() const = delete;
    NonCopyable& operator = ( const NonCopyable& ) = delete;
    NonCopyable& operator = ( NonCopyable& ) = delete;
    NonCopyable& operator = ( NonCopyable&& ) = delete;
    template<class TReturn>
    TReturn process( std::function<TReturn(const T&)> f ) {
        return f( value );
    }

};

int main( [[maybe_unused]] int argc, [[maybe_unused]]char* argv[] ) {
    typedef std::vector<int>  IntVec;
    NonCopyable< IntVec >   vec1{ 2, 3, 5 };
    double average = vec1.template process<double>( 
            []( const IntVec& vn ) {
                        int     nSum = 0;
                        int     nCount = 0;
                        for ( auto& n : vn ) {
                            nSum += n;
                            nCount++;
                        }
                        return double( nSum ) / double ( nCount );
            }
        );
    std::cout << "average = " << average << std::endl;

    //NonCopyable< std::vector<int> > vec2( vec1 );     // would lead to the following compiler error:
    /*
    src/test2_2.cpp:45:48: error: use of deleted function ‘NonCopyable<T>::NonCopyable(NonCopyable<T>&) [with T = std::vector<int>]’
    45 |     NonCopyable< std::vector<int> > vec2( vec1 );     // would lead to the following compiler error:
        |                                                ^
    src/test2_2.cpp:13:5: note: declared here
    13 |     NonCopyable( NonCopyable<T>& t ) noexcept = delete;
        |     ^~~~~~~~~~~
    */
    //vec2 = vec1;                                      // would lead to the following compiler error:
    /*
    src/test2_2.cpp:54:12: error: use of deleted function ‘NonCopyable<T>& NonCopyable<T>::operator=(NonCopyable<T>&) [with T = std::vector<int>]’
    54 |     vec2 = vec1;                                      // would lead to the following compiler error:
        |            ^~~~
    src/test2_2.cpp:20:18: note: declared here
    20 |     NonCopyable& operator = ( NonCopyable& ) = delete;
        |                  ^~~~~~~~
    */
    return 0;
}
输出:

average = 3.33333

注意:正如之前所声明的,现在有人可以注入一个函数来复制该值。

内部使用继承的示例

#include <vector> #include <functional> #include <iostream> template< typename T > class NonCopyable : public T { public: NonCopyable( const NonCopyable<T>& t ) noexcept = delete; NonCopyable( NonCopyable<T>& t ) noexcept = delete; NonCopyable( NonCopyable<T>&& t ) noexcept = delete; template< typename... Targs > NonCopyable( const Targs... args ) noexcept : T{ args... } { } operator T&() const = delete; NonCopyable& operator = ( const NonCopyable& ) = delete; NonCopyable& operator = ( NonCopyable& ) = delete; NonCopyable& operator = ( NonCopyable&& ) = delete; template<class TReturn> TReturn process( std::function<TReturn(const T&)> f ) { return f( *this ); } }; int main( [[maybe_unused]] int argc, [[maybe_unused]]char* argv[] ) { typedef std::vector<int> IntVec; NonCopyable< IntVec > vec1{ 2, 3, 5 }; vec1.push_back( 7 ); double average = vec1.template process<double>( []( const IntVec& vn ) { int nSum = 0; int nCount = 0; for ( auto& n : vn ) { nSum += n; nCount++; } return double( nSum ) / double ( nCount ); } ); std::cout << "average = " << average << std::endl; //NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error: /* src/test2_3.cpp:44:48: error: use of deleted function ‘NonCopyable<T>::NonCopyable(NonCopyable<T>&) [with T = std::vector<int>]’ 44 | NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error: | ^ src/test2_3.cpp:11:5: note: declared here 11 | NonCopyable( NonCopyable<T>& t ) noexcept = delete; | ^~~~~~~~~~~ */ //NonCopyable< IntVec > vec2 = vec1; // would lead to the following compiler error: /* src/test2_3.cpp:53:27: error: redeclaration of ‘NonCopyable<std::vector<int> > vec2’ 53 | NonCopyable< IntVec > vec2 = vec1; // would lead to the following compiler error: | ^~~~ src/test2_3.cpp:44:37: note: ‘NonCopyable<std::vector<int> > vec2’ previously declared here 44 | NonCopyable< std::vector<int> > vec2( vec1 ); // would lead to the following compiler error: | ^~~~ */ return 0; }

输出:

average = 4.25

最后一句话

所提出的方法可以防止意外复制(“不可复制且不可转让”)。

我认为这种方法是合法的,因为

protected

值阻止直接访问,并且仍然可以在派生类中进行修改,并且以同样的方式,这也适用于关键字

const

兼容性
注意:所有代码均已使用 

-std=c++20

-std=c++11

进行编译。

    

© www.soinside.com 2019 - 2024. All rights reserved.