Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 基于类型的标记分派:是否可以根据容器元素的标记对容器进行不同的标记?_C++_Templates_Typetraits - Fatal编程技术网

C++ 基于类型的标记分派:是否可以根据容器元素的标记对容器进行不同的标记?

C++ 基于类型的标记分派:是否可以根据容器元素的标记对容器进行不同的标记?,c++,templates,typetraits,C++,Templates,Typetraits,请忽略警告行,因为未使用变量,算法是虚拟示例函数 另外,很抱歉我的帖子太长了,我试着尽量缩短它 给出了以下标记类型和标记结构: namespace tags { struct ordinary_tag{}; struct special_tag {}; struct extra_special_tag {}; struct ordinary_collection_tag {}; struct special_collection_tag {};

请忽略警告行,因为未使用变量,算法是虚拟示例函数

另外,很抱歉我的帖子太长了,我试着尽量缩短它

给出了以下标记类型和标记结构:

namespace tags {

    struct ordinary_tag{}; 
    struct special_tag {}; 
    struct extra_special_tag {};

    struct ordinary_collection_tag {}; 
    struct special_collection_tag {}; 

    template<typename Type>
    struct tag 
    {
        typedef void type; 
    }; 

}
implementation
命名空间根据算法结果的类型存储算法的实现,该类型可以是任何类型,并使用特定标记进行标记。结果的标记决定了所选的算法:

namespace implementation {

template<typename Result, typename Tag>
struct algorithm {};

template<typename Result> 
struct algorithm<Result, tags::ordinary_tag>
{
    static Result apply(concrete_one const & a1, concrete_two const & a2)
    {
        Result r; 

        std::cout << "ordinary" << std::endl;
        // Modify r using a1, a2. 

        return r; 
    } 

    // Commutative algorithm. 
    static Result apply(concrete_two const & a1, concrete_one const & a2)
    {
        return apply(a2, a1); 
    }
};

template<typename Result> 
struct algorithm<Result, tags::special_tag>
{
    static Result apply(concrete_one const & a1, concrete_two const & a2)
    {
        Result r; 

        std::cout << "special" << std::endl;
        // Modify r using a1, a2.

        return r; 
    } 
};
...
某些类型的定义和标记不同:

struct first_type {}; 

namespace tags {
    // Make first_type behave as ordinary type.
    template<>
    struct tag<first_type>
    {
        typedef ordinary_tag type; 
    };
}

struct second_type {};  

namespace tags {
    // Make second_type behave as a special type.
    template<>
    struct tag<second_type>
    {
        typedef special_tag type; 
    };
}
如果名为
OrdinaryType
的人真的被标记为
普通标签
,则
enable_if
将作为
T
参数提供
容器
——这是
应该提供的
enable_if
的布尔参数。我尝试使用STL容器来保存标记为普通的
first\u type
,方法如下:

    typedef std::list<first_type> first_type_list; 
    typedef std::vector<first_type> first_type_vector; 

    first_type_list fl = algorithm<first_type_list>(c1, c2); 
    first_type_vector fv = algorithm<first_type_vector>(c1, c2); 
现在,当我不基于
OrdinaryType
的标记启用
标记
专门化时,我将其专门化为任何
OrdinaryType
,如下所示:

// Works but doesn't see that OrdinaryType should be tagged with ordinary_tag, 
// std::list<first_type> and std::vector<second_type> are both tagged ordinary_collection_tag. 
//namespace tags 
//{
    //template 
    //<
        //typename OrdinaryType,  
        //template <typename, typename> class Container, 
        //template <typename> class Allocator 
    //>
    //struct tag
    //<
        //Container<OrdinaryType, Allocator<OrdinaryType>>
    //> 
    //{
        //typedef ordinary_collection_tag type; 
    //};
//}; 
//可以工作,但看不到OrdinaryType应该使用普通的_标记进行标记,
//std::list和std::vector都被标记为普通集合标记。
//名称空间标记
//{
//模板
//<
//typename OrdinaryType,
//模板类容器,
//模板类分配器
//>
//结构标签
//<
//容器
//> 
//{
//typedef普通_集合_标签类型;
//};
//}; 
然后,像
std::vector
std::list
这样的类型都用
普通集合标签
标记,即使
第二个类型
特殊标签
标记。这是我所期望的

那么,我做错了什么

我使用的是GCC4.8.2


完整的小程序可以找到

由于还没有人回答,而且我已经找到了解决这个问题的可能方法,所以我决定发布它

我没有像在问题中那样尝试对任何容器部分地专门化
标记
,而是假设拥有一个包含元素的容器是一种一般情况。因此,
标记
模板将
类型
导出为一个集合。如果
类型
不满足此条件,模板演绎将选择另一个适合的
类型
专门化:一个用于单个元素。通过引入
集合
结构来施加该条件。任何具有
value\u type
可用的容器现在都被识别为标记元素的集合

以下是解决方案(我只是将类型的名称更改为水果名称,我想是为了使其更易于阅读):


编译器产生了相当准确的诊断:这种
struct标记的“专门化”并没有真正使用它的模板参数。@构造函数,是的,这就是我所想的,但问题仍然存在:如何专门化包含标记元素的所有容器的
tag
?现在我正试图使用
value\u type
来实现这一点,并指望使用模板推断机制,但我仍然失败了。。
struct first_type {}; 

namespace tags {
    // Make first_type behave as ordinary type.
    template<>
    struct tag<first_type>
    {
        typedef ordinary_tag type; 
    };
}

struct second_type {};  

namespace tags {
    // Make second_type behave as a special type.
    template<>
    struct tag<second_type>
    {
        typedef special_tag type; 
    };
}
concrete_one c1; 
concrete_two c2; 

first_type f1 = algorithm<first_type>(c1, c2); 

second_type f2 = algorithm<second_type>(c1, c2); 
namespace tags 
{
    // An attempt to tag all Containers with Allocator of ordinary tagged types using ordinary_collection_tag.
    template 
    <
        typename OrdinaryType,  
        template <typename, typename> class Container, 
        template <typename> class Allocator 
    >
    struct tag
    <
        typename std::enable_if 
        <
            std::is_same<typename tags::tag<OrdinaryType>::type, tags::ordinary_tag>::value, // true if OrdinaryType is tagged with ordinary_tag
            Container<OrdinaryType, Allocator<OrdinaryType>> // Use this as the T argument of enable_if
        >::type // in enable_if specialized for "true" :: typename T type; 
    > 
    {
        typedef ordinary_collection_tag type; 
    };
}
    typedef std::list<first_type> first_type_list; 
    typedef std::vector<first_type> first_type_vector; 

    first_type_list fl = algorithm<first_type_list>(c1, c2); 
    first_type_vector fv = algorithm<first_type_vector>(c1, c2); 
test-other.cpp:158:12: error: template parameters not used in partial specialization:
     struct tag
test-other.cpp:158:12: error:         ‘OrdinaryType’
test-other.cpp:158:12: error:         ‘template<class, class> class Container’
test-other.cpp:158:12: error:         ‘template<class> class Allocator’
// Works but doesn't see that OrdinaryType should be tagged with ordinary_tag, 
// std::list<first_type> and std::vector<second_type> are both tagged ordinary_collection_tag. 
//namespace tags 
//{
    //template 
    //<
        //typename OrdinaryType,  
        //template <typename, typename> class Container, 
        //template <typename> class Allocator 
    //>
    //struct tag
    //<
        //Container<OrdinaryType, Allocator<OrdinaryType>>
    //> 
    //{
        //typedef ordinary_collection_tag type; 
    //};
//}; 
#include <type_traits>
#include <iostream>
#include <list>
#include <vector>
#include <map>

namespace tags {

    struct apple_tag {}; 
    struct banana_tag {}; 

    struct apple_collection_tag {}; 
    struct banana_collection_tag {}; 

    template<typename Tag>
    struct collection {}; 

    template<>
    struct collection<apple_tag>
    {
        typedef apple_collection_tag type; 
    };

    template<>
    struct collection<banana_tag>
    {
        typedef banana_collection_tag type; 
    };


    template<typename Type>
    struct tag 
    {
        typedef typename collection<typename tag<typename Type::value_type>::type>::type type; 
    }; 

    // Select tags of pairs based on the second type. Used for maps (key, value) pairs.   
    template
    <
        typename First,
        typename Second 
    >
    struct tag<std::pair<First, Second>>
    {
        typedef typename tag<Second>::type type; 
    };
}

struct apple {}; 

namespace tags {
    template<>
    struct tag<apple>
    {
        typedef apple_tag type; 
    };
}

struct banana {}; 

namespace tags {
    template<>
    struct tag<banana>
    {
        typedef banana_tag type; 
    };
}

template<typename Type> 
struct my_container
{
    typedef Type value_type; 
};

namespace implementation {

    template<typename Type, typename Tag>
    struct function {}; 

    template<typename Type>
    struct function<Type, tags::apple_tag> 
    {
        static void apply(Type const& t)
        {
            std::cout << "apple" << std::endl;
        }
    };

    template<typename Type>
    struct function<Type, tags::banana_tag> 
    {
        static void apply(Type const& t)
        {
            std::cout << "banana" << std::endl;
        }
    };

    template<typename Type>
    struct function<Type, tags::apple_collection_tag> 
    {
        static void apply(Type const& t)
        {
            std::cout << "apple collection" << std::endl;
        }
    };

    template<typename Type>
    struct function<Type, tags::banana_collection_tag> 
    {
        static void apply(Type const& t)
        {
            std::cout << "banana collection" << std::endl;
        }
    };
}

// Value tag Dispatcher
template<typename Type>
void function(Type const & t)
{
    implementation::function<Type, typename tags::tag<Type>::type>::apply(t); 
}

int main(int argc, const char *argv[])
{
    typedef std::list<apple> apple_bag; 

    apple_bag abag; 

    function(abag); 

    typedef std::vector<apple> apple_box; 

    apple_box abox; 

    function(abox); 

    typedef std::map<int, apple> apple_orchard; 

    apple_orchard ao; 

    function (ao);

    // my_container has value_type, so it can be used as well. 
    typedef my_container<banana> banana_bag; 

    banana_bag bo; 

    function(bo); 

    return 0;
}
apple collection
apple collection
apple collection
banana collection