not необходимо поместить реализацию в файл заголовка, см. альтернативное решение в конце этого ответа.
В любом случае причина, по которой ваш код не работает, что при создании экземпляра шаблона компилятор создает новый класс с заданным аргументом шаблона. Например:
template
struct Foo
{
T bar;
void doSomething(T param) {/* do stuff using T */}
};
// somewhere in a .cpp
Foo f;
При чтении этой строки компилятор создаст новый класс (назовем его FooInt
), что эквивалентно следующему:
struct FooInt
{
int bar;
void doSomething(int param) {/* do stuff using int */}
}
Следовательно, компилятор должен иметь доступ к реализации методов, чтобы создать экземпляр с аргументом шаблона (в данном случае int
). Если эти реализации не были в заголовке, они не были бы доступны, поэтому компилятор не смог бы создать экземпляр шаблона.
Общим решением для этого является запись объявления шаблона в заголовок файла, затем реализовать класс в файле реализации (например, .tpp) и включить этот файл реализации в конец заголовка.
// Foo.h
template
struct Foo
{
void doSomething(T param);
};
#include "Foo.tpp"
// Foo.tpp
template
void Foo::doSomething(T param)
{
//implementation
}
Таким образом, реализация по-прежнему отделена от объявления, но доступен компилятору.
Другое решение состоит в том, чтобы сохранить реализацию отдельно и явно создать все экземпляры шаблона, которые вам понадобятся:
// Foo.h
// no implementation
template struct Foo { ... };
//----------------------------------------
// Foo.cpp
// implementation of Foo's methods
// explicit instantiations
template class Foo;
template class Foo;
// You will only be able to use Foo with int or float
Если мое объяснение isn ' t достаточно ясно, вы можете взглянуть на C ++ Super-FAQ по этому вопросу .
Некоторые играют в data.table
и повторно используют свою существующую substr()
логику:
library(data.table)
setDT(testdata)
cols <- paste0("v", 11:13)
new_cols <- paste0(rep(cols, 2), rep(c("a", "b"), each = length(cols)))
extra <- function(x) substr(x, 1, 4)
extrb <- function(x) substr(x, 5, 8)
testdata[, (new_cols) := c(lapply(.SD, extra), lapply(.SD, extrb)), .SDcols = cols]
> testdata
v11 v12 v13 v11a v12a v13a v11b v12b v13b
1: 00240031 00000000 00310064 0024 0000 0031 0031 0000 0064
2: 00310028 00000000 00180058 0031 0000 0018 0028 0000 0058
В base R
это может быть сделано путем циклического перебора столбцов, замены нулей между ненулевыми значениями с разделителем ,
, считывания в data.frame (read.table
) и cbind
list
наборов данных
lst1 <- lapply(testdata, function(x) {
x1 <- read.table(text = sub("(?<=[1-9])0+", ",", x, perl = TRUE),
header = FALSE, sep=",", col.names = c('a', 'b'), fill = TRUE)
replace(x1, is.na(x1), 0)})
do.call(cbind, lst1)
# v11.a v11.b v12.a v12.b v13.a v13.b
#1 24 31 0 0 31 64
#2 31 28 0 0 18 58
Это также можно сделать с помощью tidyverse
, сначала gather
перейдя в «длинный» формат, затем выполнить ион separate
и, наконец, spread
] вернемся к «широкому» формату
library(tidyverse)
gather(testdata) %>%
separate(value, into = c('a', 'b'), sep=4, convert = TRUE) %>%
gather(key1, val, a:b) %>%
unite(key, key, key1, sep="_") %>%
group_by(key) %>%
mutate(ind = row_number()) %>%
spread(key, val) %>%
select(-ind)
# A tibble: 2 x 6
# v11_a v11_b v12_a v12_b v13_a v13_b
# <int> <int> <int> <int> <int> <int>
#1 24 31 0 0 31 64
#2 31 28 0 0 18 58
Или можно использовать summarise_all
с read.table
testdata %>%
summarise_all(funs(list(read.table(text =sub("^(....)", "\\1 ", .),
header = FALSE)))) %>%
unnest
Вот идея использования очень удобных для таких операций library(splitstackshape)
,
library(splitstackshape)
cSplit(setDT(testdata)[, lapply(.SD, function(i) gsub("(.{4})", "\\1 ", i))], names(testdata), sep = ' ')
# v11_1 v11_2 v12_1 v12_2 v13_1 v13_2
#1: 24 31 0 0 31 64
#2: 31 28 0 0 18 58
.