使用不完整类型(SFINAE)无效

时间:2013-05-24 08:50:06

标签: c++ templates template-specialization sfinae

我试图在模板化结构中使用一些SFINAE。我将我的问题减少到以下内容并且可以使这项工作:

template<bool mybool>
struct test {
    void myfunc();
};

template<bool mybool>
void test<mybool>::myfunc() {
    std::cout << "test true" << std::endl;
}
template<>
void test<false>::myfunc() {
    std::cout << "test false" << std::endl;
}

int main(int argc, char ** argv) {
    test<true> foo;
    test<false> bar;
    foo.myfunc();
    bar.myfunc();
}

使用此代码,我得到结果:

test true
test false

但是,如果我想考虑具有多个模板参数的struct test,我尝试按照以下方式调整上述内容:

template<int myint, bool mybool>
struct test {
    void myfunc();
};

template<int myint, bool mybool>
void test<myint,mybool>::myfunc() {
    std::cout << "test true" << std::endl;
}
template<int myint>
void test<myint,false>::myfunc() { 
//error: invalid use of incomplete type 'struct test<myint, false>'
    std::cout << "test false" << std::endl;
}

int main(int argc, char ** argv) {
    test<1,true> foo;
    test<1,false> bar;
    foo.myfunc();
    bar.myfunc();
}

我无法使用不完整类型的'struct test'。

我走向错误的方向吗?有办法做我想做的事吗? 谢谢你的帮助!

4 个答案:

答案 0 :(得分:6)

你不能部分专门化成员函数,你应该partially specialize完整结构。以下示例将正常工作

template<int myint, bool mybool>
struct test {
    void my_func();
};

template<int myint, bool mybool>
void test<myint,mybool>::my_func() {
    std::cout << "test true" << std::endl;
}

template<int myint>
struct test<myint, false> {
   void my_func();
};

template<int myint>
void test<myint,false>::my_func() { 
//error: invalid use of incomplete type 'struct test<myint, false>'
    std::cout << "test false" << std::endl;
}

int main(int argc, char ** argv) {
    test<1,true> foo;
    test<1,false> bar;
    foo.my_func();
    bar.my_func();
}

答案 1 :(得分:3)

如果您想避免重新定义您的课程,因为不允许部分特殊化(成员)功能,您必须这样做,您可以分解您的类型。这将最大限度地减少代码的重复:

template<int myint, bool mybool>
struct test {
    char some_var;
    std::vector<int> more_var;
    void my_func();
};

更改为:

template<int myint>
struct test_static {
  protected:
    char some_var;
    std::vector<int> more_var;
};

template <int myint, bool mybool>
struct test : private test_static<myint> {
    void my_func() {
      // default case
    }
};
template <int myint>
struct test<myint,false> : private test_static<myint> {
    void my_func() {
      // special case
    }
};

当然,如果您希望所有成员都能完全了解外部,请不要首先使用protected并使用public代替private继承。

答案 2 :(得分:3)

首先查看SFINAE原则的this question以刷新我的内存,我试图在代码中获得最少冗余的结果。

我还查看了有关该主题的wikipedia文章,该文章表明我需要一个类似boost::enable_if的功能来有条件地选择您的功能实现:

// simplified version of boost::enable_if_c and disable_if_c to match your exact need

template <bool B>
struct enable_if_c {
    typedef void type;
};

struct enable_if_c<false>{};

template <bool B>
struct disable_if_c {
    typename void type;
};

struct disable_if_c<true> {};

template<bool mybool, typename T>
struct test {
    template <bool d> 
    typename enable_if_c<d>::type my_func_impl(){
        cout << "true" << endl;
    }
    template <bool d>
    typename disable_if_c<d>::type my_func_impl(){
         cout << "false" << endl;
    }
    void my_func(){ my_func_impl<mybool>(); }
};

您可以使用以下语法在结构外部定义my_func_impl实体:

 template <bool mybool, typename T>
 template <bool d>
 typename enable_if_c<d>::type test<mybool,T>::my_func_impl(){
     cout << "true" << endl;
 }

问题的棘手之处在于,您不能依赖简单的重载,因为您需要相同的函数原型,因此需要专门定义一个或另一个实现。

答案 3 :(得分:0)

您可以对diderc提供的答案稍加改进,只需稍加修改即可避免使用会污染您的函数名称的辅助函数:

而不是:

template <bool d> 
typename enable_if_c<d>::type my_func_impl(){
    cout << "true" << endl;
}
template <bool d>
typename disable_if_c<d>::type my_func_impl(){
     cout << "false" << endl;
}
void my_func(){ my_func_impl<mybool>(); }

只需写下:

template <bool d = mybool> 
typename enable_if_c<d>::type my_func(){
    cout << "true" << endl;
}
template <bool d = mybool>
typename disable_if_c<d>::type my_func(){
     cout << "false" << endl;
}

如果你可以使用C ++ 11,那么你可以用std::enable_if替换enable_if_c和disable_if_c。

(我无法评论他的答案,所以我发布了自己的答案)