【问题标题】:How to prevent non-specialized template instantiation?如何防止非专业模板实例化?
【发布时间】:2011-10-27 04:50:07
【问题描述】:

我有一个模板化的class(称之为Foo),它有几个专业。如果有人尝试使用非专业版本的Foo,我希望编译失败。

这是我实际拥有的:

template <typename Type>
class Foo
{
  Foo() { cannot_instantiate_an_unspecialized_Foo(); }

  // This method is NEVER defined to prevent linking.
  // Its name was chosen to provide a clear explanation why the compilation failed.
  void cannot_instantiate_an_unspecialized_Foo();
};

template <>
class Foo<int>
{    };

template <>
class Foo<double>
{    };

这样:

int main()
{
  Foo<int> foo;
}

工作时间:

int main()
{
  Foo<char> foo;
}

没有。

显然,编译器链仅在链接过程发生时才会抱怨。但是有没有办法让它之前抱怨?

我可以使用boost

【问题讨论】:

    标签: c++ templates boost compilation


    【解决方案1】:

    只是不要定义类:

    template <typename Type>
    class Foo;
    
    template <>
    class Foo<int> { };
    
    int main(int argc, char *argv[]) 
    {
        Foo<int> f; // Fine, Foo<int> exists
        Foo<char> fc; // Error, incomplete type
        return 0;
    }
    

    为什么会这样?仅仅是因为没有任何通用模板。已声明,是的,但未定义。

    【讨论】:

    • 非常感谢。我想我在寻找一些太复杂的东西。
    • @Schnommus 但是如果你确实定义了这个类并且它有一个 static_assert,它不应该永远不会被实例化,因为专业化匹配得更好吗?
    • 这是一个错误的决定,因为错误将在链接阶段发出,而不是在编译阶段。而且你永远不会知道你到底在哪里使用了非专业类。
    【解决方案2】:

    您可以简单地不定义基本情况:

    template <typename> class Foo;             // no definition!
    
    template <> class Foo<int> { /* ... */ };  // Foo<int> is OK
    

    【讨论】:

    • 我不敢相信我错过了...谢谢。接受了 Schnommus 的回答,因为他的声望较低。为公平起见,对此进行了投票。
    【解决方案3】:

    C++0x 的一个技巧(也可用于 C++03 static_assert 仿真,但错误消息不一定比未定义主模板更好):

    template<typename T>
    struct dependent_false: std::false_type {};
    
    template<typename Type>
    struct Foo {
        static_assert( dependent_false<Type>::value
                     , "Only specializations of Foo may be used" );
    };
    

    只有在使用主模板实例化Foo 时才会触发断言。使用static_assert( false, ... ) 会一直触发断言。

    【讨论】:

    • 一个类似的不需要输入的技巧是使用 static_assert(sizeof(Type) == 0, "...");作为替代方案,您可以使用 BOOST_STATIC_ASSERT。我个人更喜欢那些,因为当您只使用引用/指针时,上面的“不定义基本模板”可能会导致链接器错误。通常你应该停下来重新考虑一下你是否真的需要这个,因为模板是通用的,你在这里限制了
    • 这是如何工作的?您不需要为每个Specialization 定义dependent_false&lt;Specialization&gt; : std::true_type {},否则dependent_false&lt;Type&gt;::value 将始终为假?
    • @mako 这意味着总是错误的。如果你有例如Foo&lt;int&gt; 在某处定义的显式特化,那么它不应该包含这个特定的断言。因此,当 那个 特化被实例化时,不会触发任何断言——主模板与显式或部分特化无关。
    • 使用带有参数的模板而不是 false 只是为了防止 static_assert 在有人实例化非专业模板类之前停止,对吧?
    • @mako 没错。 static_assert( false ); 总是会触发。如果您有兴趣深入了解这一点,您可能需要查找相关类型和表达式(dependent_false 的名字当然来源于此)。
    猜你喜欢
    • 2010-12-26
    • 2015-08-01
    • 2018-09-28
    • 1970-01-01
    • 1970-01-01
    • 2020-07-18
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    相关资源
    最近更新 更多