将函数/构造函数参数限制为特定类型的成员

时间:2010-07-22 17:59:17

标签: c++

如果我有一个模板化的类,它将另一个类作为参数并且是从特定类型构造的,那么无论如何都要将其可能的构造值范围限制为仅属于参数类的成员吗?

所以,如果我有

template <typename T>
struct Foo {
    Foo(int v)
        : value(v) {}

    int value;
};

struct Bar {
    static const int valid1 = 6;
    static const int valid2 = 9;
    static const int valid3 = 42;
};

我可以将可以传递给Foo<Bar>的构造函数的有效值限制为Bar::valid1 ... Bar::valid3吗?

通过这个例子,我可以在Bar中使用一个具有特定名称的枚举,在Foo的构造函数中指定,它将采用枚举的成员而不是简单的整数,但是它具有任何值都可以强制转换为枚举的问题,因此很容易被破坏,更重要的是不能扩展到非整数类型。

一个强大的typedef会做我认为的伎俩,我相信有一个提升,但我正在寻找解决方案,如果可能的话我可以用标准库实现。

我考虑过函数指针,因此static const int中的Bar代替Foo,我将拥有返回值的函数,而Bar wold的构造函数接受函数指针。但是静态函数的行为就像全局函数一样,需要注意函数指针,因此在Foo中调用它时不需要Bar限定,因此可以使用任何返回int的全局函数。可以通过在T [=Bar]中不使用静态函数并在Foo中维护{{1}}的实例并针对此实例调用函数指针来使其工作,但这看起来有点乱,函数自然应该是静态的不是,我有一个结构的实例,它实际上应该只是常量的容器。

我想知道是否有标准方法可以做到这一点,或者你会推荐什么。

2 个答案:

答案 0 :(得分:0)

如果你知道你将在编译时使用的有效数字,我有一个相当hackish的解决方案。如果有效数字有可能发生变化,那么它将没有多大用处。

首先使用命名类型模板参数而不是构造函数。

template <typename T, int Bar>
struct Foo {
private:
    Foo() { }
};

注意我已将构造函数设为私有。您将无法实例化此类(或者您将收到编译时错误,这很好)。

要实例化您想要的那些,我们可以将模板专门化为这些值,并提供公共构造函数,以便您可以实例化它们。

template <typename T>
struct Foo<T, 6>{
    Foo() : value(6) { 
    }
    int value;
};

现在使用Foo<int, 6> foo是有效的,但Foo<int, 7> foo等不会编译。为每个contsraint执行此操作。 (是的,我意识到它很难看)。您可以通过创建另一个类来减少这种语法,让我们将其称为FooInternal - 您将在其中实现所有通用代码,并让每个专用类派生自它。给它一个受保护的构造函数来防止实例化。

template <typename T, int Bar>
struct FooInternal {
protected:
    FooInternal() : value(Bar) {
    }
public:
    int value ;
};

然后可以将专业化减少到一个衬里。

template<typename T> struct Foo<T, 9> : FooInternal<T, 9> {};
template<typename T> struct Foo<T, 42> : FooInternal<T, 42> {};

答案 1 :(得分:0)

忽略我的另一个答案,我再次阅读了这个问题并认为它适用于此。但是,沿着相同的路线,您可以使用私有构造函数创建结构,并使用受保护的构造函数创建另一个嵌套的结构。每个有效数字都可以从内部结构派生。这是一种强类型的枚举,我想这就是你想要的。

struct Bar {
private:
    Bar() { }

    struct BarInternal {
    protected:
        BarInternal(int v) : value(v) {}
        int value;
    public:
        operator int() { //Allow cast back to int.
            return value;
        }
    };
public:
    struct Valid1 : public BarInternal {
        Valid1() : BarInternal(6) { }
    };

    struct Valid2 : public BarInternal {
        Valid2() : BarInternal(9) { }
    };
};

然后调整模板以在其构造函数中使用Bar :: BarInternal。

template <typename T>
struct Foo {
    Foo(Bar::BarInternal v)
        : value(v) {}

    int value;
};