【问题标题】:Invalid use of incomplete type (SFINAE)不完整类型的无效使用 (SFINAE)
【发布时间】:2013-05-19 19:42:49
【问题描述】:

我正在尝试在模板结构中使用一些 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();
}

我对不完整类型“结构测试”的使用无效。

我是不是走错了方向?有没有办法做我想做的事? 感谢您的帮助!

【问题讨论】:

  • 你写foo.test()时是指foo.myfunc()吗?
  • 你在第二个例子中也拼错了myfunc。应该是my_func。请在发布之前尝试您的示例。

标签: c++ templates template-specialization sfinae


【解决方案1】:

你不能部分特化成员函数,你应该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();
}

【讨论】:

  • 好的,尝试了您的解决方案,它确实有效。但是,假设我的班级中有很多属性,我真的不想在两个结构中都声明它们。但是如果我只在第一个声明它们,我将无法从专门的访问它们。有没有办法让我不把所有的声明都加倍?
  • @Kiplaki 是的,使用某种基础/特征类型。
  • @Kiplaki 或使用false_type/true_type 调度过载。
【解决方案2】:

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

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 继承。

【讨论】:

    【解决方案3】:

    首先查看this question关于 SFINAE 原理以刷新我的记忆,我试图在代码中以最小的冗余得到您正在寻找的结果。

    我还查看了有关该主题的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;
     }
    

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

    【讨论】:

      【解决方案4】:

      您可以对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,那么你可以将 enable_if_c 和 disable_if_c 替换为std::enable_if

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

      【讨论】:

        猜你喜欢
        • 2017-10-24
        • 2010-10-13
        • 2016-04-06
        • 2017-07-28
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多