能否实际使用指针类型实例化模板?

时间:2014-03-17 17:43:06

标签: c++ templates pointers boost stl

当您在C ++中定义模板(带有类型参数)时,您可以实际传递一个指向类型的指针,例如:

MyClass<Foo*>... // edited

我想知道这是否真的使用过?因为这个问题太广泛了,让我们关注核心C ++,意思是 - 它是用在 STL还是Boost ?如果是(在STL / Boost中)是出于什么目的?

请注意我要求将指针作为参数传递(来自OUTSIDE)。使用指针传递参数INSIDE模板是另一个故事,我不会问这个问题。

更新

传递指针和使用指针之间的区别。

看看那些帖子: How is vector implemented in C++passing pointer type to template argument

myname<char*>(...

myname是一个功能。传递给模板的类型(模板,而不是函数)是指向char的指针。

现在,使用指针内部:

template <class T...
class vector {
private:
  T*                    data_;

你传递int(例如),但没有什么能阻止使用指针的模板。

我对第一个案件感兴趣,而不是第二个案件。

3 个答案:

答案 0 :(得分:2)

就像我评论的那样,我记得一个用例,其中函数将按其实际地址注册为事件回调。

这样,将为注册的每个成员函数静态生成调用成员函数的trampoline函数。

我不确定这是我实际可以使用的东西,但它确实展示了一种(设计的)方法,其中指向函数的指针模板参数可以使用。

#include <iostream>
#include <vector>

const static auto null = nullptr;

template<typename TFuncSignature>
class Callback;

template<typename R, typename A1>
class Callback<R (A1)> {
public:
    typedef R (*TFunc)(void*, A1);

        Callback() : obj(0), func(0) {}
        Callback(void* o, TFunc f) : obj(o), func(f) {}

        R operator()(A1 a1) const {
                return (*func)(obj, a1);
        }

        typedef void* Callback::*SafeBoolType;
        operator SafeBoolType () const {
                return func != 0? &Callback::obj : 0;
        }

        bool operator! () const {
                return func == 0;
        }

        bool operator== ( const Callback<R (A1)>& right ) const {
                return obj == right.obj && func == right.func;
        }

        bool operator!= ( const Callback<R (A1)>& right ) const {
                return obj != right.obj || func != right.func;
        }

private:
        void* obj;
        TFunc func;
};

template<typename R, class T, typename A1>
struct DeduceMemCallbackTag {
        template<R (T::*Func)(A1)>
        static R Wrapper(void* o, A1 a1) {
                return (static_cast<T*>(o)->*Func)(a1);
        }

        template<R (T::*Func)(A1)>
        inline static Callback<R (A1)> Bind(T* o) {
                return Callback<R (A1)>(o, &DeduceMemCallbackTag::Wrapper<Func>);
        }
};

template<typename R, typename A1>
struct DeduceStaticCallbackTag {
        template<R (*Func)(A1)>
        static R Wrapper(void*, A1 a1) {
                return (*Func)(a1);
        }

        template<R (*Func)(A1)>
        inline static Callback<R (A1)> Bind( ) {
                return Callback<R (A1)>( 0, &DeduceStaticCallbackTag::Wrapper<Func> );
        }
};

template<typename R, class T, typename A1>
DeduceMemCallbackTag<R, T, A1> DeduceMemCallback(R (T::*)(A1)) {
        return DeduceMemCallbackTag<R, T, A1>();
}

template<typename R, typename A1>
DeduceStaticCallbackTag<R, A1> DeduceStaticCallback(R (*)(A1)) {
        return DeduceStaticCallbackTag<R, A1>();
}

template <typename T1> class Event {
public:
        typedef void(* TSignature)( T1 );
        typedef Callback<void( T1 )> TCallback;

protected:
        std::vector<TCallback> invocations;
        std::vector<Event<T1>*> events;

public:
        const static int ExpectedFunctorCount = 2;

        Event () : invocations(), events() {
                invocations.reserve( ExpectedFunctorCount );
                events.reserve( ExpectedFunctorCount );
        }

        template <void (* TFunc)(T1)> void Add (  ) {
                TCallback c = DeduceStaticCallback( TFunc ).template Bind< TFunc >( );
                invocations.push_back( c );
        }

        template <typename T, void (T::* TFunc)(T1)> void Add ( T& object ) {
                Add<T, TFunc>( &object );
        }

        template <typename T, void (T::* TFunc)(T1)> void Add ( T* object ) {
                TCallback c = DeduceMemCallback( TFunc ).template Bind< TFunc >( object );
                invocations.push_back( c );
        }

        void Invoke ( T1 t1 ) {
                size_t i;
                for ( i = 0; i < invocations.size(); ++i ) {
                        invocations[i]( t1 );
                }
                for ( i = 0; i < events.size(); ++i ) {
                        (*events[i])( t1 );
                }
        }

        void operator() ( T1 t1 ) {
                Invoke( t1 );
        }

        size_t InvocationCount ( ) {
                return events.size( ) + invocations.size( );
        }

        template <void (* TFunc)(T1)> bool Remove ( ) {
                TCallback target = DeduceStaticCallback( TFunc ).template Bind< TFunc >( );
                for ( size_t i = 0; i < invocations.size(); ++i ) {
                        TCallback& inv = invocations[i];
                        if ( target == inv ) {
                                invocations.erase( invocations.begin() + i );
                                return true;
                        }
                }
                return false;
        }

        template <typename T, void (T::* TFunc)(T1)> bool Remove ( T& object ) {
                return Remove<T, TFunc>( &object );
        }

        template <typename T, void (T::* TFunc)(T1)> bool Remove ( T* object ) {
                TCallback target = DeduceMemCallback( TFunc ).template Bind< TFunc >( object );
                for ( size_t i = 0; i < invocations.size(); ++i ) {
                        TCallback& inv = invocations[i];
                        if ( target == inv ) {
                                invocations.erase( invocations.begin() + i );
                                return true;
                        }
                }
                return false;
        }

};

namespace IntStatic {
    void VoidTest    ()         { std::cout << "INTO THE VOID"         << std::endl; }
    void IntTest     (int num)  { std::cout << "Got myself a "         << num  << " !"    << std::endl; }
    void IntTest2    (int num)  { std::cout << "Now _I_ Got myself a " << num  << " !"    << std::endl; }
}
struct Int {
    void Test        (int num)  { std::cout << num  << " on the inside of a class... ?"   << std::endl; }
    void Test2       (int num)  { std::cout << num  << " on the inside of a struct, yo !" << std::endl; }
    static void Test3(int snum) { std::cout << snum << " on the inside of a class... ?"   << std::endl; }
};

int main(int argc, char* argv[]) {
    Event<int> intev;
    Int i;
    intev.Add<Int, &Int::Test>(i);
    intev.Add<&IntStatic::IntTest>();
    intev.Add<&IntStatic::IntTest2>();
    //intev.Add( Int::Test3 );
    intev(20);
    intev.Remove<&IntStatic::IntTest>();
    intev.Remove<&IntStatic::IntTest>();
    intev.Remove<Int, &Int::Test>(i);
    //intev.Remove( Int::Test3 );
    //intev.Remove( i, &Int::Test );
    intev(20);
    return 0;
}

实际代码由@ThePhD着名,归功于他。见 Live on Coliru

答案 1 :(得分:2)

指针只是一种类型,因此您可以使用some_template<T>的任何地方使用some_template<T*>

基于STL的标准库部分在许多地方使用std::iterator_traits<Iter>Iter可能是指针类型。

std::unique_ptr<T, D>的某些实现使用类型std::tuple<T*, D>的数据成员(例如,这适用于GCC的实现,但这是一个您不应该关心的实现细节。)< / p>

答案 2 :(得分:2)

您可以通过专业化具有不同的语义,例如:

template <typename T> struct referred_sizeof  { 
    static constexpr size_t value = sizeof(T);
};

现在,这可能是专门的:

template <typename T> struct referred_sizeof<T*> { 
    static constexpr size_t value = sizeof(T);
};

template <typename T> struct referred_sizeof <boost::optional<T*> > { 
    static constexpr size_t value = sizeof(boost::optional<T*>) + sizeof(T);
};

这导致了这种行为:

static_assert(referred_sizeof <int>::value == referred_sizeof <int*>::value, "passes");

此应用程序是其他人在评论中提到的实现 traits classes

的应用程序

完整示例,为boost::tuple<...>添加专业化只是为了好玩:看到它 Live On Coliru

int main()
{
    report<double>();
    report<double *>();
    report<boost::optional<double> >();
    report<boost::optional<double> *>();
    report<boost::optional<double *> *>();

    report<boost::tuple<boost::optional<double *> *, double> >();
}

打印

void report() [with T = double]: referred_sizeof is 8
void report() [with T = double*]: referred_sizeof is 8
void report() [with T = boost::optional<double>]: referred_sizeof is 16
void report() [with T = boost::optional<double>*]: referred_sizeof is 16
void report() [with T = boost::optional<double*>*]: referred_sizeof is 24
void report() [with T = boost::tuples::tuple<boost::optional<double*>*, double>]: referred_sizeof is 40

完全实施以供参考

#include <iostream>
#include <boost/optional.hpp>
#include <boost/tuple/tuple.hpp>

template <typename... Ts> struct referred_sizeof;

// base cases
template <typename T> struct referred_sizeof<T> { 
    static constexpr size_t value = sizeof(T);
};

template <typename T> struct referred_sizeof<T*> { 
    static constexpr size_t value = referred_sizeof<T>::value;
};

template <typename T> struct referred_sizeof<boost::optional<T*> > { 
    static constexpr size_t value = sizeof(boost::optional<T*>) + referred_sizeof<T>::value;
};

template <typename... Ts> struct referred_sizeof<boost::tuple<Ts...> > { 
    static constexpr size_t value = referred_sizeof<Ts...>::value; // TODO take into account padding/alignment overhead?
};

static_assert(referred_sizeof<int>::value == referred_sizeof<int*>::value, "passes");

template <typename T1, typename... Ts> struct referred_sizeof<T1, Ts...> {
    static constexpr size_t value = referred_sizeof<T1>::value + referred_sizeof<Ts...>::value;
};

template <typename T>
void report()
{
    std::cout << __PRETTY_FUNCTION__ << ": referred_sizeof is " << referred_sizeof<T>::value << "\n";
}