Проверьте правильность шаблона функции в C ++ 14 при использовании -Waddress - PullRequest
0 голосов
/ 12 октября 2018

При компиляции этого кода с помощью -Waddress:

#include <iostream>
#include <memory>
#include <string.h>

template <typename T, void (*func)(T*) = nullptr>
struct Caller {
    Caller(T* ptr = nullptr)
    {
        std::cout
            << "Creating caller " << ptr
            << ", is function " << std::is_function<decltype(func)>()
            << ", is null " << std::is_null_pointer<decltype(func)>()
            << ", function is " << func
            << std::endl;

        if (func)
        {
            std::cout << "Running for " << ptr << " func " << func << std::endl;
            func(ptr);
        }
    }
};

void free_char(char *c) { free(c); }

int main() {
    Caller<char, free_char>(strdup("Test"));
    Caller<const char>("Test2");
    return 0;
}

произойдет сбой:

/tmp/foo.cpp: In instantiation of ‘Caller<T, func>::Caller(T*) [with T = char; void (* func)(T*) = free_char]’:
/tmp/foo.cpp:36:40:   required from here
/tmp/foo.cpp:13:33: warning: the address of ‘void free_char(char*)’ will never be NULL [-Waddress]

Обходной путь использует что-то вроде if (auto f = func) f(ptr);, но я бы хотелесть что-то, что статически проверяется во время компиляции.

В этом решении упоминается использование специализации шаблона, но часть, в которой мы здесь работаем со структурой, это тот случай, когда я 'Я хотел бы использовать статические проверки шаблона.

1 Ответ

0 голосов
/ 12 октября 2018

Как насчет простого предоставления функции no-op по умолчанию вместо нулевого указателя?Это избавляет от if в целом и делает код чище в целом.

template<typename T>
void no_op(T*) {}

template <typename T, void (*func)(T*) = no_op<T>>
struct Caller {
    static_assert(func != nullptr, "don't pass nullptr");
    Caller(T* ptr = nullptr)
    {
        std::cout
            << "Creating caller " << ptr
            << ", is function " << std::is_function<decltype(func)>()
            << ", is null " << std::is_null_pointer<decltype(func)>()
            << ", function is " << func
            << std::endl;

        std::cout << "Running for " << ptr << " func " << func << std::endl;
        func(ptr);
    }
};
...