Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/163.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 - Fatal编程技术网

C++ 确保无变体的类型安全

C++ 确保无变体的类型安全,c++,templates,C++,Templates,考虑以下类别: template <typename T> class A { public: A(B<T> b) : b_(b) { } T foo() { return b_.foo(); } private: class B<T> b_; } template typename<T> class B { public: T foo(); } 模板 甲级{ 公众: A(B):B_uB(B){} T foo

考虑以下类别:

template <typename T>
class A {
 public:
  A(B<T> b) : b_(b) { }

  T foo() {
    return b_.foo();
  }
 private:
  class B<T> b_;
}

template typename<T>
class B {
 public:
  T foo();
}
模板
甲级{
公众:
A(B):B_uB(B){}
T foo(){
返回b_.foo();
}
私人:
B类;
}
模板类型名
B类{
公众:
T foo();
}
这很好地加强了跨堆栈的键入(您可以不断添加更多层并在单个类型上键入它们。但是,我希望在第二层上有两个不同的选项:

template <typename T, typename Y>
class A {
 public:
  T foo() {
    return b_.foo();
  }
  Y foo() {
    return c_.foo();
  }

 private:
  class B<T> b;
  class C<Y> c;

}

template typename<T>
class B {
 public:
  T foo();
}

template typename<T>
class C {
 public:
  T foo();
}
模板
甲级{
公众:
T foo(){
返回b_.foo();
}
余福义(){
返回c_.foo();
}
私人:
乙级;
丙级;;
}
模板类型名
B类{
公众:
T foo();
}
模板类型名
C类{
公众:
T foo();
}
有什么方法可以用多个类型名模板化类并实现这些方案吗?请注意,在某些情况下,
T
Y
可能是相同的,因此必须有更多的区别(例如
B
vs
C


我相信我可以有多个函数foo1和foo2返回不同的值。但是,我正在寻找可扩展的解决方案,客户可以提供他们自己的类型名,可能不止两个。理想情况下,会有一个重载(可能获取内部类的标识?)

你的想法很难理解,但我想你的意思是获取一个
模板typename
列表和相等数量的
typename
并构建其压缩应用程序的产品

// wrap a template<typename> typename into a normal type
// e.g. index_of_v<std::vector, std::vector> fails, but
// index_of_v<suspend<std::vector>, suspend<std::vector>> gives 0
template<template<typename> typename>
struct suspend { };
// search for X in Xs and produce a static constexpr std::size_t member values containing the index
// This is just the natural functional programming way to search a linked list
// indexOf(x, Nil) = undefined
// indexOf(x, Cons(y, xs)) = x == y ? 0 : 1 + indexOf(x, xs)
// deriving from std::integral_constant is really just noise;
// could be replaced with an explicit member definition
// but it's considered idiomatic to do this for some reason that I've forgotten
template<typename X, typename... Xs>
struct index_of { }; // base case, the default template only fires when Xs is empty, so the index is undefined 
template<typename X, typename... Xs>
struct index_of<X, X, Xs...> : std::integral_constant<std::size_t, 0> { }; // if X is at the top of the list, it has index 0
template<typename X, typename Y, typename... Xs>
struct index_of<X, Y, Xs...> : std::integral_constant<std::size_t, index_of<X, Xs...>::value + 1> { }; // if it isn't, find it's index relative to the tail of the list, then shift it to be the index relative to the whole
// instead of writing index_of<X, Xs..>::value, write index_of_v<X, Xs...>
// this is a convention that you see in the standard library
template<typename X, typename... Xs>
inline constexpr std::size_t index_of_v = index_of<X, Xs...>::value;

// a class cannot have two lists of variadic template parameters
// the easiest thing to do is split the templating into two stages
// the outer template, choices, takes a list of templates as parameters
// template<typename T> class std::vector;
// int is a "base" type, so you can pass int to std::vector<int>
// but std::vector is not like int: std::vector<std::vector> is meaningless
// std::vector alone is just a template<typename> typename
// a function from types to types
template<template<typename> typename... Cs>
struct choices {
    // 2nd "stage" takes the list of "normal" types
    template<typename... Ts>
    class type {
        // apply each template to the corresponding base type
        // the resulting list of base types is passed to std::tuple
        // there's a "field" for each Cs<Ts> inside the tuple
        std::tuple<Cs<Ts>...> parts;

        public:
        // hopefully self-explanatory
        type(Cs<Ts>... parts) : parts(parts...) { }

        // return the result of calling foo() on the container identified by C
        template<template<typename> typename C>
        auto foo() {
            // we know the list of all the Cs,
            // so just find the index of C in it and pass that to std::get
            // then pass in parts to get the desired object, then call foo()
            return std::get<index_of_v<suspend<C>, suspend<Cs>...>>(parts).foo();
        }
    };

    // there's no luck for deducing Cs, since in order to *get* to types we need to specify Cs
    // (choices::type is not a thing, you always write choices<Cs...>::type)
    // But you can deduce `Ts`, by looking at the things contained in each container
    // so, deduction guide
    template<typename... Ts>
    type(Cs<Ts>...) -> type<Ts...>;
};

如果返回类型不同,则多态性不适用于同名函数。但是,对于
t
=
Y
的情况,您可能会考虑模板专门化或处理此问题。即使t=Y,那么
t=a.foo();
会做什么?(如果t!=Y,您可以通过两次转换返回代理。)非常感谢您的评论。我正在考虑允许将类型标识传递到不同的多态函数中。这样行吗?@gruszczy:您的代码显然很混乱。在一个地方,您使用
B
作为类型名:
a(B条)
。但是在另一个例子中,你使用
B
作为模板名称:
B
不能同时是这两个,那么它是哪一个呢?还有,
B
和模板
条之间的关系是什么?为什么在不同的位置有许多虚假的
呢?嘿@gruszczy,你的问题看起来真的不清楚。您能添加一些可能使用的简短示例吗?实际上,您可以使用
std::enable_if
,使用相同名称但返回不同类型的函数。但是,如果没有您期望的示例,我无法告诉您确切的方法。这看起来是我需要的,但老实说,我在理解上有问题(我主要是问,因为我对模板不是很在行)。你会不会很友好,通过各行解释它们的用途?而且,这似乎是非常具体的(至少目前是这样),因为gcc不喜欢扣减指导(我想错了)。gcc是否有这样的功能?还有一条评论:这是一个惊人的壮举,但似乎需要很强的模板知识。如果我不再需要choices::type中的一个foo函数和无限数量的参数,它是否可以简化?我认为这不需要任何“强大的知识”唯一可能被认为是复杂的事情是
index\u of
,但我想你会在图书馆里找到它。是的,如果你删除
foo
,那么你就不需要
index\u of
,这就是复杂性所在。但是,像这样删除
foo
,似乎无法解决问题。但不完全确定如何删除为了让GCC不再是它自己。cppreference告诉我,演绎指南在一个类中应该可以正常工作。你可以尝试创建某种包装类,但在一个类问题上,你会遇到整个两个可变模板参数包,我认为你不能再为给定的容器集命名部分专门化。
template<typename T>
struct B {
    T x;
    B(T x) : x(x) { }
    T foo() { return x; }
};
using A1 = choices<B>;
void demonstration1() {
    A1::type a(B(5)); // note the deduction guide at work
    std::cout << "B: " << a.foo<B>() << "\n";
}

template<typename T>
struct C {
    T x;
    C(T x) : x(x) { }
    T foo() { return -x; } // keeping it interesting
};
using A2 = choices<B, C>;
void demonstration2() {
    A2::type a(B('a'), C(5));
    std::cout << "B: " << a.foo<B>() << "; C: " << a.foo<C>() << "\n";
}