简体   繁体   English

在编译时键入specialized

[英]Type specialization at compile-time

I'm writing a class which shares several different features with std::function (or at least the classes are in many ways similar). 我正在编写一个与std::function共享几个不同特性的类(或者至少类在很多方面类似)。 As you all know std::function is instantiated by specifying the template parameters (ie std::function<void (std::string&)> ), it is the same for my class. 正如大家都知道std::function是通过指定模板参数实例化(即std::function<void (std::string&)> ),它是我的课一样。 I have an exception though, I want to specialize a single function in my class, if the return value is void ( std::function<"return value" ("parameters"> ). I need this to be done at compile time, and I just can't make it work as it should. Here is some test code for explanation: 我有一个例外,不过,我想在我的课,专门的单一功能,如果返回值是无效的( std::function<"return value" ("parameters">我需要这在编译时完成,我只是不能使它工作。这是一些测试代码的解释:

#include <iostream>
#include <type_traits>

template <typename T> class Test { };

template <typename Ret, typename... Args>
class Test<Ret (Args...)>
{
public:
    Ret operator()(Args...)
    {
        if(std::is_void<Ret>::value)
        {
             // Do something...
        }

        else /* Not a void function */
        {
            Ret returnVal;
            return returnVal;
        }
    }
};

int main(int argc, char * argv[])
{
    Test<void (char)> test;
    test('k');
}

As you can clearly see, if the compiler does not remove the 'else' branch in the above test, my code will try to create a void value (ie void returnVal; ). 正如您可以清楚地看到的,如果编译器在上面的测试中没有删除'else'分支,我的代码将尝试创建一个void值(即void returnVal; )。 The problem is that the compiler does not remove the branch so I end up with a compiler error: 问题是编译器没有删除分支,所以我最终得到一个编译器错误:

./test.cpp: In instantiation of 'Ret Test::operator()(Args ...) [with Ret = void; ./test.cpp:在'Ret Test :: operator()(Args ...)的实例化中[含Ret = void; Args = {char}]': ./test.cpp:27:10: required from here ./test.cpp:18:8: error: variable or field 'returnVal' declared void ./test.cpp:19:11: error: return-statement with a value, in function returning 'void' [-fpermissive] Args = {char}]':。/ test.cpp:27:10:从这里需要./test.cpp:18:8:错误:变量或字段'returnVal'声明为void ./test.cpp:19:11 :error:带有值的return语句,在函数返回'void'[-fpermissive]

One would normally use std::enable_if combined with std::is_void , the problem is that I don't want to specialize on the function template, but on the class template. 通常会将std::enable_ifstd::is_void结合使用,问题在于我不想专注于函数模板,而是在模板上。

template <typename Ret, typename... Args>
class Test<Ret (Args...)>
{
public:
    typename std::enable_if<!std::is_void<Ret>::value, Ret>::type 
    Ret operator()(Args...)
    {
        Ret returnVal;
        return returnVal;
    }

    typename std::enable_if<std::is_void<Ret>::value, Ret>::type 
    Ret operator()(Args...)
    {
        // It's a void function
        // ...
    }
};

If I use the above code instead I end up with even more errors and without a solution 如果我使用上面的代码,我会得到更多的错误,没有解决方案

./test.cpp:11:2: error: expected ‘;’ at end of member declaration
./test.cpp:11:2: error: declaration of ‘typename std::enable_if<(! std::is_void<_Tp>::value), Ret>::type Test<Ret(Args ...)>::Ret’
./test.cpp:6:11: error:  shadows template parm ‘class Ret’
./test.cpp:11:24: error: ISO C++ forbids declaration of ‘operator()’ with no type [-fpermissive]
./test.cpp:18:2: error: expected ‘;’ at end of member declaration
./test.cpp:18:2: error: declaration of ‘typename std::enable_if<std::is_void<_Tp>::value, Ret>::type Test<Ret(Args ...)>::Ret’
./test.cpp:6:11: error:  shadows template parm ‘class Ret’
./test.cpp:18:24: error: ISO C++ forbids declaration of ‘operator()’ with no type [-fpermissive]
./test.cpp:18:6: error: ‘int Test<Ret(Args ...)>::operator()(Args ...)’ cannot be overloaded
./test.cpp:11:6: error: with ‘int Test<Ret(Args ...)>::operator()(Args ...)’
./test.cpp: In member function ‘int Test<Ret(Args ...)>::operator()(Args ...)’:
./test.cpp:22:2: warning: no return statement in function returning non-void [-Wreturn-type]
./test.cpp: In instantiation of ‘int Test<Ret(Args ...)>::operator()(Args ...) [with Ret = void; Args = {char}]’:
./test.cpp:28:10:   required from here
./test.cpp:13:7: error: variable or field ‘returnVal’ declared void
./test.cpp: In member function ‘int Test<Ret(Args ...)>::operator()(Args ...) [with Ret = void; Args = {char}]’:
./test.cpp:15:2: warning: control reaches end of non-void function [-Wreturn-type]

I'm sorry if I'm just plain dumb, and the answer is obvious. 如果我只是愚蠢的话,我很抱歉,答案很明显。 I'm fairly new to templates and I couldn't find a suiting answer in any of the other threads/questions. 我对模板很新,我在其他任何线程/问题中找不到合适的答案。

There are a few things that are not exactly clear from your description, so I will start with the most general answer. 从您的描述中有一些不完全清楚的事情,所以我将从最常见的答案开始。

Assuming that the template has other functions for which the behavior must be kept the same, and you only want to redefine the behavior for that particular function, the simplest answer is to split the template in two, and use inheritance to merge them. 假设模板具有必须保持相同行为的其他函数,并且您只想重新定义该特定函数的行为,最简单的答案是将模板拆分为两个,并使用继承来合并它们。 At this point you can use partial template specialization on the base template: 此时,您可以在基本模板上使用部分模板特化:

template <typename T, typename... Args>
struct tmpl_base {
   T operator()( Args... args ) {
       //generic
   }
};
template <typename... Args>
struct tmpl_base<void,Args...> {
   void operator()( Args... args ) {
   }
};

template <typename Ret, typename... Args>
class Test<Ret (Args...)> : tmp_base<Ret,Args...> {
   // do not declare/define operator(), maybe bring the definition into scope:
   using tmp_base<Ret,Args...>::operator();

   // Rest of the class

If this is the only function in your template, then partial specialization is a much simpler solution that does not require abusing inheritance. 如果这是模板中唯一的功能,那么部分特化是一个更简单的解决方案,不需要滥用继承。

One solution is partially specializing your class template. 一种解决方案是部分专门化您的类模板。

#include <iostream>
#include <type_traits>

template <typename T> class Test { };

template <typename Ret, typename... Args>
class Test<Ret (Args...)>
{
public:
    Ret operator()(Args...)
    {

        std::cout<<"non-void function"<<std::endl;
        Ret returnVal;
        return returnVal;

    }
};

template <typename... Args>
class Test<void (Args...)>
{
public:
    void operator()(Args...)
    {

        std::cout<<"void function"<<std::endl;
    }
};


int main(int argc, char * argv[])
{
    Test<void (char)> test;
    test('k');
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM